<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Offshore Custom Software Development Company | Binary Studio, Ukraine</title>
	<atom:link href="https://binary-studio.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://binary-studio.com</link>
	<description>Looking for software developers?&#60;br /&#62;       Set up a Dedicated Development Team with us!</description>
	<lastBuildDate>Tue, 31 May 2022 06:48:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0</generator>
	<item>
		<title>Analytical Shadows: Still Too Early?</title>
		<link>https://binary-studio.com/2022/05/26/analytical-shadows-still-too-early/</link>
					<comments>https://binary-studio.com/2022/05/26/analytical-shadows-still-too-early/#respond</comments>
		
		<dc:creator><![CDATA[Anton Duzenko]]></dc:creator>
		<pubDate>Thu, 26 May 2022 15:01:00 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=26204</guid>

					<description><![CDATA[<p>The not-so-recent introduction of Shader Storage Buffer Object in OpenGL 4.3 (2012) opened a great variety of potential applications. It’s finally possible to do work on big data, like vertex arrays. Not that it was completely impossible before, but fortunately, we can forget about legacy tricks and workarounds that used to&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/05/26/analytical-shadows-still-too-early/">Analytical Shadows: Still Too Early?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><span style="font-weight: 400;">The not-so-recent introduction of Shader Storage Buffer Object in OpenGL 4.3 (2012) opened a great variety of potential applications. It’s finally possible to do work on big data, like vertex arrays. Not that it was completely impossible before, but fortunately, we can forget about legacy tricks and workarounds that used to be  required and go straight to writing shader code.</span></p>
<h2><span style="font-weight: 400;">Pre-requisites</span></h2>
<p><span style="font-weight: 400;">This article assumes that the reader is familiar with 3D computer graphics concepts and techniques, such as </span><a href="https://en.wikipedia.org/wiki/Shadow_mapping"><span style="font-weight: 400;">shadows</span></a><span style="font-weight: 400;">, </span><a href="https://en.wikipedia.org/wiki/Shader"><span style="font-weight: 400;">shaders</span></a><span style="font-weight: 400;">, </span><a href="https://thebookofshaders.com/11/"><span style="font-weight: 400;">noise</span></a><span style="font-weight: 400;">, frame blending.</span></p>
<h2><span style="font-weight: 400;">Exposure</span></h2>
<p><span style="font-weight: 400;">3D shadows implementation, as smooth and casual as it looks in any of your video games, has been a source of controversy, pain, and confusion for all 3D programmers for generations. Countless proposals have been made, building on top of each other, and all have one point in common - make the next shadow implementation a little less ugly and buggy than the current one.</span></p>
<p><span style="font-weight: 400;">For sheer fun, how many Shadow Mapping </span><a href="https://en.wikipedia.org/wiki/Shadow_mapping#Soft_Shadows"><span style="font-weight: 400;">algorithms </span></a><span style="font-weight: 400;">can you remember off the top of your head? SSM, PCF, PCSS, CSM, VSM, …? They all have cool names and look great on their original PDF proposal screenshots, but somehow after a little time  another, even more advanced algo comes up - rinse and repeat. Not mentioning the shadow volumes, having enjoyed their moment of fame in 2004 before departing into oblivion.</span></p>
<p><span style="font-weight: 400;">At some point you get to the question: are shadows inherently impossible to get right? How hard is it to test if a point in space receives light or is occluded? Let’s find out.</span></p>
<h2><span style="font-weight: 400;">Idea</span></h2>
<p><span style="font-weight: 400;">A simple and reliable algorithm only takes a few hours of web search to develop, assuming you have a little previous experience with OpenGL. All we need is</span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">The light source position in 3D space</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">A list of occluders, as an array of triangles</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">The point position to test whether it’s occluded or lit</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">A routine to test if the ray from light to point intersects any of the occluders</span></li>
</ul>
<p><span style="font-weight: 400;">Obviously this needs to happen on the per-pixel basis, so the code goes into the fragment shader. The test function is easy to </span><a href="https://www.google.com/search?client=firefox-b-d&amp;sxsrf=ALeKk018ipp1Q-3a8BQxdl1KX7fTBgbuAg:1619426561531&amp;q=rayTriangleIntersect&amp;nfpr=1&amp;sa=X&amp;ved=2ahUKEwiog8KHwpvwAhVvo4sKHYUVB20QvgUoAXoECAEQNg&amp;biw=1857&amp;bih=1089"><span style="font-weight: 400;">find </span></a><span style="font-weight: 400;">on the web:</span></p>
<pre class="crayon-plain-tag">float rayTriangleIntersect(
	vec3 orig, vec3 dir,
	vec3 v0, vec3 v1, vec3 v2)
{
...
}</pre>
<p><span style="font-weight: 400;">I’m omitting the function body code here as it may hurt your eyes if your linear algebra skill is not advanced enough. Anyway, it’s the foundation the rest of the experiment is built upon. All we need to know for now is whether the given triangle casts a shadow on the current fragment.</span></p>
<p><img class="wp-image-26210 size-full aligncenter" src="https://binary-studio.com/wp-content/uploads/2022/05/image1.png" alt="" width="300" height="341" srcset="https://binary-studio.com/wp-content/uploads/2022/05/image1.png 300w, https://binary-studio.com/wp-content/uploads/2022/05/image1-264x300.png 264w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p><span style="font-weight: 400;">We can now call this function for every occluder triangle in the list and we have a mathematically precise answer for the problem. </span></p>
<h2><span style="font-weight: 400;">It works</span></h2>
<p><span style="font-weight: 400;">With a little trial and error the simple shadow test does not take long to complete:</span></p>
<p><img class="alignnone wp-image-26211 size-full" src="https://binary-studio.com/wp-content/uploads/2022/05/image2.png" alt="" width="1857" height="1200" srcset="https://binary-studio.com/wp-content/uploads/2022/05/image2.png 1857w, https://binary-studio.com/wp-content/uploads/2022/05/image2-300x194.png 300w, https://binary-studio.com/wp-content/uploads/2022/05/image2-1024x662.png 1024w, https://binary-studio.com/wp-content/uploads/2022/05/image2-768x496.png 768w, https://binary-studio.com/wp-content/uploads/2022/05/image2-1536x993.png 1536w, https://binary-studio.com/wp-content/uploads/2022/05/image2-624x403.png 624w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<p><span style="font-weight: 400;">So all good then? Expectedly, no. This approach can’t handle more than a handful of occluder triangles in real time. The benchmarked low-power Radeon 550 (64-bit) can barely do a hundred triangles at 60FPS. Surely, a high-end GPU can do much more than this, and you can optimize the calculation and get another 2x-3x boost, but that goes out of scope of this experiment.</span></p>
<h2><span style="font-weight: 400;">Hardship</span></h2>
<p><span style="font-weight: 400;">What’s more important at this stage, the rendering result is not any better than e.g. shadow volumes. For reference, the latter are also pixel-perfect, but they suffer from the fact that their native output is strictly hard shadows with no half-tones. Screen space approximation filters exist, but they tend to give unrealistic, sometimes plain wrong results.</span></p>
<p><span style="font-weight: 400;">Still shadow volumes are a great deal faster than what we came up with so far. Maybe we can get soft shadows to compensate for that? </span></p>
<p><span style="font-weight: 400;">Well, the common approach for soft shadows would be to average multiple samples, but that’s based on the fact that a single shadow test, as ugly and buggy it has been, is quite fast and you can fit multiples of them in your render cost budget.</span></p>
<p><span style="font-weight: 400;">Single analytical shadow test is very expensive, so averaging multiples of these is already a bad idea.</span></p>
<p><span style="font-weight: 400;">Still, we do have a couple of tricks up our sleeve here.</span></p>
<h2><span style="font-weight: 400;">Noise</span></h2>
<p><span style="font-weight: 400;">To soften the shadow edges we will use a noise function. For each fragment on the screen we will take a random point on the light source surface and use it instead of the single light source position above. The noise function is different for every frame so the pixels on the screen flicker with time.</span></p>
<p><img class="alignnone wp-image-26212 size-full" src="https://binary-studio.com/wp-content/uploads/2022/05/image3.png" alt="" width="1857" height="1200" srcset="https://binary-studio.com/wp-content/uploads/2022/05/image3.png 1857w, https://binary-studio.com/wp-content/uploads/2022/05/image3-300x194.png 300w, https://binary-studio.com/wp-content/uploads/2022/05/image3-1024x662.png 1024w, https://binary-studio.com/wp-content/uploads/2022/05/image3-768x496.png 768w, https://binary-studio.com/wp-content/uploads/2022/05/image3-1536x993.png 1536w, https://binary-studio.com/wp-content/uploads/2022/05/image3-624x403.png 624w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<p><span style="font-weight: 400;">To workaround the pixel flickering we will now apply frame blending.</span></p>
<p><img class="alignnone wp-image-26213 size-full" src="https://binary-studio.com/wp-content/uploads/2022/05/image4.png" alt="" width="1857" height="1200" srcset="https://binary-studio.com/wp-content/uploads/2022/05/image4.png 1857w, https://binary-studio.com/wp-content/uploads/2022/05/image4-300x194.png 300w, https://binary-studio.com/wp-content/uploads/2022/05/image4-1024x662.png 1024w, https://binary-studio.com/wp-content/uploads/2022/05/image4-768x496.png 768w, https://binary-studio.com/wp-content/uploads/2022/05/image4-1536x993.png 1536w, https://binary-studio.com/wp-content/uploads/2022/05/image4-624x403.png 624w" sizes="(max-width: 1857px) 100vw, 1857px" /></p>
<p><span style="font-weight: 400;">At this point we finally have accurate soft shadows. The only visible downside is when the light is moving the shadows become hard until the movement stops but for moving lights it’s not critical.</span></p>
<h2><span style="font-weight: 400;">Conclusion</span></h2>
<p><span style="font-weight: 400;">While analytical shadows are obviously slow (while accurate), it’s interesting to test how they fare on current graphics hardware. At the same time in a short list of situations, when occluders are actually low-poly shapes (e.g. room walls), they can be even used directly with little or no modification. Curiously, it also supports partially-translucent occluder materials, unlike shadow maps or shadow volumes.</span></p>
<p><span style="font-weight: 400;">Source code available <a href="https://github.com/duzenko/shadows2020">here</a>.</span></p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/05/26/analytical-shadows-still-too-early/">Analytical Shadows: Still Too Early?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2022/05/26/analytical-shadows-still-too-early/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Block or inl&#060;i&#062;ne?</title>
		<link>https://binary-studio.com/2022/04/28/block-or-inline/</link>
					<comments>https://binary-studio.com/2022/04/28/block-or-inline/#respond</comments>
		
		<dc:creator><![CDATA[Vladyslav Zubko]]></dc:creator>
		<pubDate>Thu, 28 Apr 2022 17:46:19 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=25391</guid>

					<description><![CDATA[<p>This image contains around 50 screenshots from random articles and courses, where the authors state that tags in HTML are divided into two types - block and inline. This is wrong. HTML tags are divided into&#160;7&#160;types. In this article we will learn about them and how to use them correctly. The&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/04/28/block-or-inline/">Block or inl&lt;i&gt;ne?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter size-large"><img width="751" height="351" src="https://binary-studio.com/wp-content/uploads/2022/04/image9.jpg" alt="" class="wp-image-25398" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image9.jpg 751w, https://binary-studio.com/wp-content/uploads/2022/04/image9-300x140.jpg 300w, https://binary-studio.com/wp-content/uploads/2022/04/image9-624x292.jpg 624w" sizes="(max-width: 751px) 100vw, 751px" /></figure></div>



<p class="has-line-data">This image contains around 50 screenshots from random articles and courses, where the authors state that tags in HTML are divided into two types - block and inline.</p>



<p class="has-line-data"><strong>This is wrong.</strong></p>



<p class="has-line-data">HTML tags are divided into&nbsp;<strong>7</strong>&nbsp;types. In this article we will learn about them and how to use them correctly.</p>



<h2 class="code-line"><a id="The_Problem_6"></a>The Problem</h2>



<p class="has-line-data">Let’s imagine that we have a task where we need to make a markup of a form. Something like this:</p>



<pre class="crayon-plain-tag">// src/components/sign-up/components/register-form/register-form.jsx
 
&lt;form className=&quot;register-form&quot;&gt;
 &lt;p className=&quot;register-form__control-wrapper&quot;&gt;
   &lt;CustomSelect label=&quot;Type:&quot; options={[]} /&gt;
 &lt;/p&gt;
&lt;/form&gt;</pre>



<pre class="crayon-plain-tag">// src/components/common/custom-select/custom-select.jsx

const CustomSelect = ({ label, options }) =&amp;gt; (
  &lt;div classname=&quot;custom-select&quot;&gt;
    &lt;label classname=&quot;custom-select__label&quot;&gt;
      {label}
      &lt;select classname=&quot;custom-select__control&quot;&gt;
        {options.map((it) =&amp;gt; (
          &lt;option value=&quot;{it.value}&quot;&gt;{it.label}&lt;/option&gt;
        ))}
      &lt;/select&gt;
    &lt;/label&gt;
  &lt;/div&gt;
);</pre>



<p class="has-line-data">But when we open the browser we see this:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="265" height="128" src="https://binary-studio.com/wp-content/uploads/2022/04/image4.jpg" alt="" class="wp-image-25418"/></figure></div>



<p class="has-line-data">Hmm, the custom select component outside of the&nbsp;<code>p</code>&nbsp;element? An extra&nbsp;<code>p</code>&nbsp;appeared?</p>



<p class="has-line-data">One more example:</p>



<pre class="crayon-plain-tag">// src/components/sign-up/components/users/users.jsx
 
&lt;div className=&quot;table-wrapper&quot;&gt;
 &lt;CustomTable&gt;
   {users.map((user) =&gt; (
     &lt;tr&gt;
       &lt;td&gt;{user.name}&lt;/td&gt;
       &lt;td&gt;{user.role}&lt;/td&gt;
     &lt;/tr&gt;
   ))}
 &lt;/CustomTable&gt;
&lt;/div&gt;</pre>



<pre class="crayon-plain-tag">// src/components/common/custom-table/custom-table.jsx

const CustomTable = ({ children }) =&gt; (
  &lt;table className=&quot;custom-table&quot;&gt;
    {children}
  &lt;/table&gt;
);</pre>



<p class="has-line-data">Let’s open a browser:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="193" height="222" src="https://binary-studio.com/wp-content/uploads/2022/04/image3.jpg" alt="" class="wp-image-25400"/></figure></div>



<p class="has-line-data">What is going on…</p>



<p class="has-line-data">This is how the browser behaves when we try to nest one element incorrectly within another.</p>



<h2 class="code-line"><a id="7_types_of_HTML_Element_83"></a>7 types of HTML Element</h2>



<p class="has-line-data">Each element in HTML falls into zero or more categories that group elements with similar characteristics together and has its own content model and other nuances and features. For example,&nbsp;<a href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element">the p element</a>:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="1024" height="441" src="https://binary-studio.com/wp-content/uploads/2022/04/image5-1024x441.jpg" alt="" class="wp-image-25403" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image5-1024x441.jpg 1024w, https://binary-studio.com/wp-content/uploads/2022/04/image5-300x129.jpg 300w, https://binary-studio.com/wp-content/uploads/2022/04/image5-768x331.jpg 768w, https://binary-studio.com/wp-content/uploads/2022/04/image5-624x269.jpg 624w, https://binary-studio.com/wp-content/uploads/2022/04/image5.jpg 1251w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure></div>



<p class="has-line-data">HTML Element content types:</p>



<ul><li class="has-line-data" data-line-start="90" data-line-end="91"><a href="https://html.spec.whatwg.org/multipage/dom.html#metadata-content-2">Metadata content</a>&nbsp;— information for browsers, search engines and etc. (everything in the&nbsp;<code>&lt;head&gt;</code>);</li><li class="has-line-data" data-line-start="91" data-line-end="92"><a href="https://html.spec.whatwg.org/multipage/dom.html#flow-content-2">Flow content</a>&nbsp;— content (everything in the&nbsp;<code>&lt;body&gt;</code>);</li><li class="has-line-data" data-line-start="92" data-line-end="93"><a href="https://html.spec.whatwg.org/multipage/dom.html#phrasing-content-2">Phrasing content</a>&nbsp;— document text and small text elements in paragraphs;</li><li class="has-line-data" data-line-start="93" data-line-end="94"><a href="https://html.spec.whatwg.org/multipage/dom.html#sectioning-content-2">Sectioning content</a>&nbsp;— semantic sections of the document;</li><li class="has-line-data" data-line-start="94" data-line-end="95"><a href="https://html.spec.whatwg.org/multipage/dom.html#heading-content-2">Heading content</a>&nbsp;— headlines;</li><li class="has-line-data" data-line-start="95" data-line-end="96"><a href="https://html.spec.whatwg.org/multipage/dom.html#embedded-content-category">Embedded content</a>&nbsp;— images, video, audio and etc;</li><li class="has-line-data" data-line-start="96" data-line-end="97"><a href="https://html.spec.whatwg.org/multipage/dom.html#interactive-content-2">Interactive content</a>&nbsp;— what the user is interacting with.</li></ul>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="600" height="300" src="https://binary-studio.com/wp-content/uploads/2022/04/image7.jpg" alt="" class="wp-image-25404" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image7.jpg 600w, https://binary-studio.com/wp-content/uploads/2022/04/image7-300x150.jpg 300w" sizes="(max-width: 600px) 100vw, 600px" /></figure></div>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img src="https://binary-studio.com/wp-content/uploads/2022/04/image2.jpg" alt="" class="wp-image-25405" width="580" height="290" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image2.jpg 600w, https://binary-studio.com/wp-content/uploads/2022/04/image2-300x150.jpg 300w" sizes="(max-width: 580px) 100vw, 580px" /></figure></div>



<p class="has-text-align-center">HTML Element content types</p>



<p class="has-line-data"><em>When you try to nest one tag in another incorrectly, browser starts fixing errors&nbsp;<strong>at its discretion</strong>&nbsp;<strong>without asking</strong>.</em></p>



<h2 class="code-line"><a id="Lets_play_Can_x_be_nested_in_y_103"></a>Let’s play. Can&nbsp;<code>&lt;x&gt;</code>&nbsp;be nested in&nbsp;<code>&lt;y&gt;</code>?</h2>



<p class="has-line-data">Open the&nbsp;<a href="https://html.spec.whatwg.org/multipage/semantics.html#semantics">documentation</a>&nbsp;and try to find the answer yourself ?</p>



<pre class="crayon-plain-tag">&lt;li&gt;
 &lt;p&gt;?&lt;/p&gt;
&lt;/li&gt;</pre>



<p class="has-line-data"><strong>Yes, you can!</strong><br><a href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-li-element">The&nbsp;<code>li</code>&nbsp;element</a>&nbsp;content model —&nbsp;<code>flow content</code>.<br><a href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element">The&nbsp;<code>p</code>&nbsp;element</a>&nbsp;categories —&nbsp;<code>flow content</code>,&nbsp;<code>palpable content</code>.</p>



<pre class="crayon-plain-tag">&lt;header&gt;
 &lt;section&gt;?&lt;/section&gt;
&lt;/header&gt;</pre>



<p class="has-line-data"><strong>Yes, you can!</strong><br><a href="https://html.spec.whatwg.org/multipage/sections.html#the-header-element">The&nbsp;<code>header</code>&nbsp;element</a>&nbsp;content model —&nbsp;<code>flow content</code>, but with no&nbsp;<code>header</code>&nbsp;or&nbsp;<code>footer</code>&nbsp;element descendants.<br><a href="https://html.spec.whatwg.org/multipage/sections.html#the-section-element">The&nbsp;<code>section</code>&nbsp;element</a>&nbsp;categories —&nbsp;<code>flow content</code>,&nbsp;<code>sectioning content</code>,&nbsp;<code>palpable content</code>.</p>



<pre class="crayon-plain-tag">&lt;p&gt;
 &lt;div&gt;?&lt;/div&gt;
&lt;/p&gt;</pre>



<p class="has-line-data"><strong>No, you can’t!</strong><br><a href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element">The&nbsp;<code>p</code>&nbsp;element</a>&nbsp;content model —&nbsp;<code>phrasing content</code>.<br><a href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-div-element">The&nbsp;<code>div</code>&nbsp;element</a>&nbsp;categories —&nbsp;<code>flow content</code>,&nbsp;<code>palpable content</code>.</p>



<p class="has-line-data">How can we test ourselves and our application? One of the tools is the official&nbsp;<a href="https://validator.w3.org/">W3C validator</a>.</p>



<p class="has-line-data">You can upload the file, paste the code or use the link to your application.</p>



<p class="has-line-data">Let’s try using one of our examples at the beginning of the article:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="636" height="636" src="https://binary-studio.com/wp-content/uploads/2022/04/image6.png" alt="" class="wp-image-25407" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image6.png 636w, https://binary-studio.com/wp-content/uploads/2022/04/image6-300x300.png 300w, https://binary-studio.com/wp-content/uploads/2022/04/image6-150x150.png 150w, https://binary-studio.com/wp-content/uploads/2022/04/image6-624x624.png 624w" sizes="(max-width: 636px) 100vw, 636px" /></figure></div>



<p class="has-line-data">The result:</p>



<figure class="wp-block-image size-large"><img width="676" height="708" src="https://binary-studio.com/wp-content/uploads/2022/04/image8.png" alt="" class="wp-image-25408" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image8.png 676w, https://binary-studio.com/wp-content/uploads/2022/04/image8-286x300.png 286w, https://binary-studio.com/wp-content/uploads/2022/04/image8-624x654.png 624w" sizes="(max-width: 676px) 100vw, 676px" /></figure>



<p class="has-line-data">The validator and the browser did not know what we meant when we nested the&nbsp;<code>&lt;tr&gt;</code>&nbsp;element inside the&nbsp;<code>&lt;div&gt;</code>&nbsp;element. The browser tried to fix the errors itself (because of this, we got the wrong markup) and the validator talks about the stray start&nbsp;<code>&lt;tr&gt;</code>&nbsp;tag in the markup. Which is not strange since according to the&nbsp;<a href="https://html.spec.whatwg.org/multipage/tables.html#the-tr-element">documentation</a>, the&nbsp;<code>&lt;tr&gt;</code>&nbsp;element can only be used inside the table tags (<code>&lt;thead&gt;</code>,&nbsp;<code>&lt;tbody&gt;</code>,&nbsp;<code>&lt;tfoot&gt;</code>,&nbsp;<code>&lt;table&gt;</code>).</p>



<h2 class="code-line"><a id="Can_I_Include_175"></a>Can I Include</h2>



<p class="has-line-data">Of course you don’t have to memorize all types of content but sometimes you should look there when you are not sure whether something is broken.</p>



<p class="has-line-data">By analogy with&nbsp;<a href="https://caniuse.com/">Can I Use</a>, the&nbsp;<a href="https://caninclude.glitch.me/">Can Include</a>&nbsp;tool has been developed that can help us with this.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="777" height="458" src="https://binary-studio.com/wp-content/uploads/2022/04/image1.jpg" alt="" class="wp-image-25409" srcset="https://binary-studio.com/wp-content/uploads/2022/04/image1.jpg 777w, https://binary-studio.com/wp-content/uploads/2022/04/image1-300x177.jpg 300w, https://binary-studio.com/wp-content/uploads/2022/04/image1-768x453.jpg 768w, https://binary-studio.com/wp-content/uploads/2022/04/image1-624x368.jpg 624w" sizes="(max-width: 777px) 100vw, 777px" /></figure></div>



<p class="has-line-data">With this tool, we can check if we can nest one element into another.</p>



<p class="has-line-data">We can check this in the official documentation but with CanInclude we can do it faster since its interface is simpler for this than the documentation.</p>



<h2 class="code-line"><a id="Conclusions_185"></a>Conclusions</h2>



<p class="has-line-data">HTML may break or may not look as expected and that is okay. It is not bad HTML, it just has its own rules. You just need to understand that something could break just because of incorrect nesting and know where it can be quickly checked.</p>



<p class="has-line-data">Each HTML element has its own category and its own type of content that it can have. In general, there are&nbsp;<strong>7</strong>&nbsp;types of content that expect a certain nesting into each other.</p>



<p class="has-line-data">You&nbsp;<em>don’t have to memorize them all</em>&nbsp;but sometimes when you have doubts or something is broken you can look at the&nbsp;<a href="https://html.spec.whatwg.org/multipage/dom.html#kinds-of-content">documentation</a>, check your code in the HTML&nbsp;<a href="https://validator.w3.org/">validator</a>&nbsp;or use the&nbsp;<a href="https://caninclude.glitch.me/">CanInclude tool</a>&nbsp;to check yourself.</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/04/28/block-or-inline/">Block or inl&lt;i&gt;ne?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2022/04/28/block-or-inline/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How we attract and train the best minds</title>
		<link>https://binary-studio.com/2022/02/01/how-we-attract-and-train-the-best-minds/</link>
					<comments>https://binary-studio.com/2022/02/01/how-we-attract-and-train-the-best-minds/#respond</comments>
		
		<dc:creator><![CDATA[Daryna Mishchuk]]></dc:creator>
		<pubDate>Tue, 01 Feb 2022 12:18:12 +0000</pubDate>
				<category><![CDATA[Process]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Binary Studio Academy]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=25110</guid>

					<description><![CDATA[<p>Binary Studio Academy is our award-winning program for the most talented and brightest computer science graduates in Eastern Europe. Every year, the program runs for three intense months, during which we teach the fundamentals of professional software development using the latest technologies and best practices in the industry. The mission of&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/02/01/how-we-attract-and-train-the-best-minds/">How we attract and train the best minds</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><span style="font-weight: 400;">Binary Studio Academy is our award-winning program for the most talented and brightest computer science graduates in Eastern Europe. Every year, the program runs for three intense months, during which we teach the fundamentals of professional software development using the latest technologies and best practices in the industry.</span></p>



<figure class="wp-block-image"><img width="1560" height="1040" src="https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n.jpg" alt="" class="wp-image-25151" srcset="https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n.jpg 1560w, https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n-300x200.jpg 300w, https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n-1024x683.jpg 1024w, https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n-768x512.jpg 768w, https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n-1536x1024.jpg 1536w, https://binary-studio.com/wp-content/uploads/2022/02/244357161_4391645740890965_3609046769209315004_n-624x416.jpg 624w" sizes="(max-width: 1560px) 100vw, 1560px" /></figure>



<p><span style="font-weight: 400;">The mission of Binary Studio Academy is to transform talented and motivated students into qualified engineers capable of building world-class software. We help novice developers deepen and sharpen their existing programming knowledge, driving breakthroughs in their understanding of development theory while guiding them to mastery of modern frameworks and technologies.</span></p>



<p><span style="font-weight: 400;">An extremely competitive acceptance rate (0.5%) enables us to find exceptional talents. Participants are chosen based on their tech and soft skills as well as their performance during the selection rounds, including an entrance exam, three homework assignments, English test and a Zoom interview with representatives of our Academy program. Almost 80% of our company are graduates of the Academy, and all of our senior engineers went through the Binary Studio Academy <span style="color: #ff9900;"><a style="color: #ff9900;" href="https://binary-studio.com/academy/">program</a></span>. These same engineers are now the ones who write the curriculum and ultimately choose who graduates the course, as well as who is offered a job at Binary.</span></p>



<figure class="wp-block-image"><img width="2560" height="1389" src="https://binary-studio.com/wp-content/uploads/2022/02/2-min-scaled.jpg" alt="hiring funnel, IT academy" class="wp-image-25125" srcset="https://binary-studio.com/wp-content/uploads/2022/02/2-min-scaled.jpg 2560w, https://binary-studio.com/wp-content/uploads/2022/02/2-min-300x163.jpg 300w, https://binary-studio.com/wp-content/uploads/2022/02/2-min-1024x556.jpg 1024w, https://binary-studio.com/wp-content/uploads/2022/02/2-min-768x417.jpg 768w, https://binary-studio.com/wp-content/uploads/2022/02/2-min-1536x833.jpg 1536w, https://binary-studio.com/wp-content/uploads/2022/02/2-min-2048x1111.jpg 2048w, https://binary-studio.com/wp-content/uploads/2022/02/2-min-624x339.jpg 624w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>



<p><span style="font-weight: 400;">Binary Studio is an early innovator in online education. Back in 2015, we launched our internal learning management system specific to the needs of our students. Our </span><span style="color: #ff9900;"><a style="color: #ff9900;" href="https://dribbble.com/shots/16557469-Learning-Management-System-UI"><span style="font-weight: 400;">Academy LMS</span></a></span><span style="font-weight: 400;"> platform is an educational project designed for interaction between students, coaches and educational managers. It allows users to create, handle and assign home tasks and tests to be completed by students, rate students’ homework, monitor their progress as well as create and manage groups of students. Our coaches provide all lectures and assignments on this platform which makes the education process far easier and more efficient.</span></p>



<p></p>



<h2 style="margin-top: 70px;margin-bottom: 40px;"><b>Building MVP projects from scratch</b></h2>



<p><span style="font-weight: 400;">Over the course of seven weeks, students work in teams to produce MVP-level web and mobile applications. </span><span style="font-weight: 400;">Currently, there are six main technological tracks at Binary Studio Academy -</span><span style="font-weight: 400;">&nbsp;JS, .NET, Java, PHP, Mobile, and QA. </span><span style="font-weight: 400;">Academists develop state-of-the-art web platforms with a complex front-end, structured back-end, and the use of several cloud services. Although the projects are not sold to clients, the development conditions are as close to the real deal as possible. Each project’s team consists of developers and QA engineers who conduct online daily standup meetings. In addition to this, each project has a Product Owner, who participates in meetings from time to time, proposes new requirements, and offers feedback on the platform’s development.</span></p>



<figure class="wp-block-image"><img width="2560" height="1389" src="https://binary-studio.com/wp-content/uploads/2022/02/1-min-scaled.jpg" alt="" class="wp-image-25122" srcset="https://binary-studio.com/wp-content/uploads/2022/02/1-min-scaled.jpg 2560w, https://binary-studio.com/wp-content/uploads/2022/02/1-min-300x163.jpg 300w, https://binary-studio.com/wp-content/uploads/2022/02/1-min-1024x555.jpg 1024w, https://binary-studio.com/wp-content/uploads/2022/02/1-min-768x417.jpg 768w, https://binary-studio.com/wp-content/uploads/2022/02/1-min-1536x833.jpg 1536w, https://binary-studio.com/wp-content/uploads/2022/02/1-min-2048x1111.jpg 2048w, https://binary-studio.com/wp-content/uploads/2022/02/1-min-624x339.jpg 624w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>



<h2><b>What value does the Academy bring to our customers?</b></h2>



<p><span style="font-weight: 400;">We don’t simply hire engineers, we acquire and nurture talents - this philosophy differs Binary Studio’s position on the market. Among the core values our approach brings to the customers:</span></p>



<ul><li><span style="font-weight: 400;"><strong>Binary Studio concentrates exclusively on the best specialists</strong>, whose skills are ideally suited to solving the specific issues of the platform that our clients need. We tailor our Academy training specifically around the projects and technologies our clients are working with.</span></li><li><span style="font-weight: 400;"><strong>We mainly work with small, medium-sized businesses and start-ups.</strong> In this industry, the cost of a mistake is too high. That is why we exclusively select those people who have a high universality of skills and abilities. The result is a group of versatile and skilled developers who can switch from front-end to back-end, web and mobile, and are ready to do so on the fly when needed.</span></li><li><span style="font-weight: 400;"><strong>Binary Studio keeps technical professionals engaged.</strong> Motivation and permanent growth are the essential requirements of modern, top-notch engineers - we know this through over a decade’s worth of experience on the market. Therefore, we provide opportunities to continuously develop, learn and create dream side projects for our engineers using the latest technologies and resources. This allows us to maintain an ideal microclimate in the team, encouraging deep involvement and sky-high motivation.</span></li><li><span style="font-weight: 400;"><strong>We attract and train the best minds.</strong> Binary Studio Academy is a totally free hands-on program that supports, educates, and scales unique talents. At the core of our program, students create an MVP-level platform within just a couple of months.&nbsp;</span></li></ul>



<p></p>



<h2><span style="font-weight: 400;">Below are some fantastic projects built from scratch which our students worked on during Binary Studio Academy 2021.</span></h2>



<p><strong><span style="color: #ff9900;font-size:22px">Perflow - music service</span></strong></p>



<p><span style="font-weight: 400;">A solution inspired by Spotify, where users can create their own playlists and listen to themed selections. The web-application allows users to listen to music in different quality albums, create different playlists, create a library of liked content, share music with friends, and play a collaborative playlist together. There is also a mobile application with data synchronization.&nbsp;</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> .NET 5, Entity Framework Core 5.0, MSSQL, Azure Blob Storage, Firebase, Dapper, MediatR Ocelot API Gateway, SignalR, RabbitMQ, ffmpeg,&nbsp; Angular, Semantic UI, SASS.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/PERFLOW_dark_gif2-min-1.gif" alt="Perflow - music service" class="wp-image-25135"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px;"><b>CodeTrainer - development skills trainer</b></span></p>



<p><span style="font-weight: 400;">CodeTrainer is an online educational platform for software developers where users can exchange their knowledge by solving programming puzzles. Users can add their own challenges and create collections by adding different challenges. The solution also includes such features like feedback gathering, clan creation, fighting for honorable places in the community, etc.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> TypeScript, NodeJS, Express.js, PostgreSQL, TypeORM, RabbitMQ, Firebase, Socket.io, JWT,&nbsp; AWS S3, React, Redux/Saga, SCSS, Docker.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/CodeTrainer_gif.gif" alt="CodeTrainer - development skills trainer" class="wp-image-25120"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>Scout - smart HR-platform</b></span></p>



<p><span style="font-weight: 400;">A web application for speeding up hiring, automation of personnel management processes, centralization of all information about employees, automation of the recruitment process of the best candidates, management of employee time offs, tracking employee involvement, performance evaluation, and several other features. The application utilizes machine learning and CV parsing.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> ASP.NET Core, Entity Framework Core, MSSQL, Elasticsearch, Dapper, SQL, MongoDB, CQRS, Docker, AWS, Amazon S3, Amazon Comprehend, Amazon Textract, JWT, SMTP, Vault by Hashicorp, TS, Angular, Angular Material, SСSS, MediatR, GitHub Actions.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/Scout_gif.gif" alt="Scout - smart HR-platform" class="wp-image-25119"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>Infostack - corporate knowledge organizer</b></span></p>



<p><span style="font-weight: 400;">A web-based application designed to store and organize the information that is a result of team collaborations. It allows company teams to keep detailed records like project timelines and plans, specifications and requirements, meeting summaries, step-by-step processes, etc. Within the app, users can create workspaces, add collaborators, manage user profiles, pages, permissions, etc. The solution also includes such features like notifications, following pages, live page editing, integration with GitHub repositories, and several other features.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> HTML, SCSS, TypeScript, Bootstrap, React, Redux, Node.js, Express.js, TypeORM, PostgreSQL, WebSockets, Elasticsearch, AWS S3.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/Infostack_gif.gif" alt="Infostack - corporate knowledge organizer" class="wp-image-25118"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>Slidez - interactive presentations application</b></span></p>



<p><span style="font-weight: 400;">A service for interactive presentations that allows speakers to share access and grant viewing rights to others. This solution allows users real-time communication with your audience, by providing an editor plugin for Google Slides, so users can integrate interactions into existing presentations. Users will have to install Google App Script addon and Google Chrome extension to access full functionality. After adding interactive elements, users can enter presentation mode and present as usual. This Google Chrome Extension will detect interactive slides and replace them with real-time updating elements, such as Q&amp;A screens and polls. Participant's don't have to install any additional software - they can use any browser they like, scan QR code and access live event interactions.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> Java 11, Spring, Hibernate, WebSockets(Spring), PostgreSQL, React, Redux Toolkit, WebSockets (SockJS + STOMP), Material UI, TypeScript, Google App Script, Chrome Extension API, AWS services (S3, Route53, CloudFront, Elastic Beanstalk, RDS, ACM, CloudWatch), GithubActions, Sentry.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/Slidez_gif.gif" alt="Slidez - interactive presentations application" class="wp-image-25117"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>Jabber - podcast platform</b></span></p>



<p><span style="font-weight: 400;">A platform for recording, storing, and supporting podcasts. The solution allows you to record a podcast in real time (people can go in and comment on the podcast while recording). Users can create favorite podcast lists, leave comments and “likes.” A private podcast option is also available.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> TS, React, Redux, SASS, React Native, NodeJS, Express, Knex, Objection, JWT, PostgreSQL, Sockets, WebRTC.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/Jabber_gif.gif" alt="Jabber - podcast platform" class="wp-image-25116"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>MindBridge - electronic publishing platform</b></span></p>



<p><span style="font-weight: 400;">A new generation of content creation tools inspired by Medium and Github. It is a platform where readers find articles on interesting articles, and where participants can share their writing on any topic. Users can create their own personal page, publish posts, leave comments, follow and unfollow other users, change profile information, save quotes from article text and create drafts of their posts. The service allows you to share your Medium-style stories and collaborate with other authors using a community-based approach similar to Github.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> Java 11, Spring, Lombok, Mapstruct, Hibernate, Flyweight, Elasticsearch, JUnit, Websockets, OAuth2 social auth, Postgresql, TypeScript, React, Redux, Redux-toolkit, Sagas, Websockets.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/MindBridge_gif.gif" alt="MindBridge - electronic publishing platform" class="wp-image-25115"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>Watchdog - project quality analysis platform</b></span></p>



<p><span style="font-weight: 400;">The platform is similar to Sentry, Raygun, and Loader.io and allows you to analyze the quality of projects, track errors and perform stress testing. The main goal of the project is to monitor project issues affecting end users in real time. The platform provides issue details including stack trace, breadcrumbs, method/class name, OS, device, browser, location, host, and more. It can be used for both kinds of projects, for servers and client-oriented projects. Users can identify problems more quickly, enjoying visual timeline views, charts, tables and receive email reports if a new issue occurred. Also, clients can perform load testing without typing code to verify how their servers will respond to high load. They can flexibly set up tests in the portal and run them as many times as they need to.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> .NET 5, REST, SignalR, RabbitMQ, MS SQL Server, Entity Framework Core,&nbsp; Azure, JWT, Firebase, Elasticsearch, Kibana, Docker, SendGrid, StackOverflow API, Angular, Prime NG, HTML5/CSS3/SASS.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/Watchdog_gif-min.gif" alt="Watchdog - project quality analysis platform" class="wp-image-25124"/></figure>



<p></p>



<p><span style="color: #ff9900;font-size:22px"><b>HypeCrafter - fundraising platform</b></span></p>



<p><span style="font-weight: 400;">This platform helps people create their own fundraising projects and attract sponsors. The user can support somebody’s idea and donate towards its realization. There are several features such as recommendations for project authors and investors, statistics on top themes, diagrams of hype dynamic on certain themes, information about related projects and their current state, and many more.</span></p>



<p><span style="font-weight: 400;"><strong>Technology stack:</strong> Node.JS, Typescript, PostgreSQL, MongoDB, ElasticSearch, RabbitMQ, Bootstrap, React, Redux, Redux-saga, Stripe, Express, Passport.JS, ChartJS, JWT, i18n, SASS, Socket.io, Docker, Sentry.io, Cron, React Native.</span></p>



<figure class="wp-block-image"><img width="1200" height="630" src="https://binary-studio.com/wp-content/uploads/2022/02/HypeCrafter_gif.gif" alt="HypeCrafter - fundraising platform" class="wp-image-25114"/></figure>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/02/01/how-we-attract-and-train-the-best-minds/">How we attract and train the best minds</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2022/02/01/how-we-attract-and-train-the-best-minds/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Developing VS Code extension to resolve your dev team pains</title>
		<link>https://binary-studio.com/2022/01/18/developing-vs-code-extension-to-resolve-your-dev-team-pains/</link>
					<comments>https://binary-studio.com/2022/01/18/developing-vs-code-extension-to-resolve-your-dev-team-pains/#respond</comments>
		
		<dc:creator><![CDATA[Maksym Slobodianyk]]></dc:creator>
		<pubDate>Tue, 18 Jan 2022 08:08:55 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=24986</guid>

					<description><![CDATA[<p>VS Code extension is a really powerful tool that can add any functionality to your IDE which isn't pre built-in. The extensions marketplace contains many solutions for different purposes. From ones that can make work with your git repository more efficient like GitLense to some that were made just for fun&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/01/18/developing-vs-code-extension-to-resolve-your-dev-team-pains/">Developing VS Code extension to resolve your dev team pains</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>VS Code extension is a really powerful tool that can add any functionality to your IDE which isn't pre built-in. The extensions marketplace contains many solutions for different purposes. From ones that can make work with your git repository more efficient like <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLense</a> to some that were made just for fun like <a href="https://www.youtube.com/watch?v=ApR-kNXxLUs">Instagram-like stories</a> for developers. But does it make sense to develop VS Code extension just for your team to resolve developer pains that are relevant only for your project? That’s what I’m going to talk about in this article.</p>
<h2><strong>Why do we need a special tool?</strong></h2>
<p>To explain how this idea came to my mind, I should briefly describe to you the project that I was working on for the last year. It is a cross-platform desktop data modeling application that uses React.js and Electron under the hood. For the purpose of handling data from many DB types, clouds, and schema registries, we deliver application plugins for each supported vendor. In our case, each plugin is a directory with configs and js files that are stored on the GitHub repository. To install a plugin means to clone or to download the directory from the app repo and put it into the plugin's home folder. It has over 30 plugins for now and this number is growing. Unlike users, we always need all plugins to be installed for development purposes. This makes a kind of a mess.</p>
<p>When you try to open a certain plugin development folder through the VS Code “open recent…” it’s common that you don’t have one that you are searching for there. And then you surf the folder where all plugins are located trying to find the one you need. Needless to say, it's a painful job.</p>
<p>Another case is updating plugins. It’s uncommon for users to have installed many plugins, which is why we don’t have a button like “update all” and have just “update” for each plugin, but it usually gets annoying to us to update 5 plugins one by one after a release wave.</p>
<p>The last inconvenient thing that I noticed after a couple of months on the project is plugins testing. It’s a usual case when we need a certain version of a plugin to reproduce a bug or one from a teammate fork and so on and so forth. This requires you to go to your browser, find the plugin repository, clone or just download its files and then place them into the correct directory. In other words, there was no way to obtain the required version of the code in a smooth way.</p>
<p>These three points pushed me to start developing my pet project which is now converted into a tool that is used by my teammates.</p>
<h2><strong>Why VS Code extension?</strong></h2>
<p>I started by choosing the technologies for the tool. The first thing I thought about was some kind of desktop app. However, one of the most valuable points for me was that it should be so handy that you could access the tool with a click and it must be one that doesn't interrupt your development process. Unfortunately, an app in a separate window couldn’t satisfy this purpose. The second point was cross-platform accessibility. Most of our team code using Ubuntu machines, but some of us use macOS and Windows. At the same time, all of us use VS Code as the main IDE. That was the point when VS Code extension popped into my head. It seemed to me so integrated into the coding process and so powerful that I decided to use it for an MVP.</p>
<h2><strong>MVP</strong></h2>
<p>Unfortunately, I didn't find any good external tutorial on how to start developing my own extension, so I started from the guide on the VS code <a href="https://code.visualstudio.com/api">website</a>. There is an extension guides <a href="https://code.visualstudio.com/api/extension-guides/overview">section</a> that has a bunch of usage examples of different extension APIs. The section contains enough information to start and get acquainted with extension anatomy. I browsed different APIs and found a <a href="https://code.visualstudio.com/api/extension-guides/tree-view">TreeView API</a> which became the core thing that allowed me to list all plugins and action buttons.</p>
<p>To become acquainted with the TreeView API, let's build a sample extension that will use a tree view to display a simple JSON structure. By the way, it is a simplified version of the documentation browser in our team's extension. You can find the complete source code of this sample extension on my <a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example">GitHub</a>.</p>
<p>Here is a documentation config.</p>
<pre class="crayon-plain-tag">{
    "root": [
        {
            "title": "App configuration chapter",
            "link": "https://www.google.com.ua/",
            "links": [
                {
                    "title": "First link",
                    "link": "https://www.google.com.ua/"
                },
                {
                    "title": "Second link",
                    "link": "https://www.google.com.ua/"
                }
            ]
        },
        {
            "title": "App development chapter",
            "link": "https://www.google.com.ua/",
            "links": [
                {
                    "title": "Third link",
                    "link": "https://www.google.com.ua/"
                }
            ]
        }
    ]
}</pre>
<p>It contains chapters in the root array. And links related to each chapter.</p>
<p>The steps for adding a tree view are to contribute the view in your <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/package.json">package.json</a></code>, create a <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/providers/DocumentationProvider.ts">TreeDataProvider</a></code>, and register the <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/providers/DocumentationProvider.ts">TreeDataProvider</a></code></p>
<p>First, you have to let VS Code know that you are contributing a View Container using the&nbsp;<a href="https://code.visualstudio.com/api/references/contribution-points#contributes.viewsContainers">contributes.viewsContainers</a> Contribution Point in <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/package.json">package.json</a></code>.</p>



<pre class="crayon-plain-tag">&quot;viewsContainers&quot;: {
	&quot;activitybar&quot;: [
		{
			&quot;id&quot;: &quot;simple-tree-view&quot;,
			&quot;title&quot;: &quot;Simple tree view&quot;,
			&quot;icon&quot;: &quot;resources/logo.svg&quot;
		}
	]
}</pre>



<p>Also, you have to contribute a view using the&nbsp;<a href="https://code.visualstudio.com/api/references/contribution-points#contributes.views">contributes.viewsContainers</a> Contribution Point in&nbsp;<code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/package.json">package.json</a></code>.</p>



<pre class="crayon-plain-tag">&quot;views&quot;: {
	&quot;simple-tree-view&quot;: [ //viewsContainer views belog to
		{
			&quot;id&quot;: &quot;documentation-browser&quot;, 
			&quot;name&quot;: &quot;documentation browser ?&quot;,
			&quot;when&quot;: &quot;config.SimpleTreeView.showDocumentationBrowser&quot;
		}
	]
}</pre>



<p>The second step is to provide data to the view you registered so that VS Code can display the data in the view. To do so, you should first implement the&nbsp;<a class="notion-link-token notion-enable-hover" href="https://code.visualstudio.com/api/references/vscode-api#TreeDataProvider" target="_blank" rel="noopener noreferrer" data-token-index="1" data-reactroot=""><span class="link-annotation-unknown-block-id-555083687">TreeDataProvider</span></a>. Our&nbsp;<a class="notion-link-token notion-enable-hover" href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/providers/DocumentationProvider.ts" target="_blank" rel="noopener noreferrer" data-token-index="3" data-reactroot=""><span class="link-annotation-unknown-block-id--776685493">TreeDataProvider</span></a>&nbsp;will provide documentation config data. There are two necessary methods in this API that you need to implement:</p>
<ul>
<li><code>getChildren(element?: T): ProviderResult&lt;T[]&gt;</code> - Implement this to return the children for the given&nbsp;<code>element</code>&nbsp;or root (if no element is passed). When the user opens the Tree View, the&nbsp;<code>getChildren</code>&nbsp;method will be called without an&nbsp;<code>element</code> and if they expand the Tree View item the&nbsp;<code>getChildren</code>&nbsp;method will be called with this item as an element.</li>
<li><code>getTreeItem(element: T): TreeItem | Thenable&lt;TreeItem&gt;</code> - Implement this to return the UI representation (<a href="https://code.visualstudio.com/api/references/vscode-api#TreeItem">TreeItem</a>) of the element that gets displayed in the view.</li>
</ul>



<pre class="crayon-plain-tag">export class DocumentationProvider implements TreeDataProvider&lt;BasicTreeItem&gt; {
		getTreeItem(element: Chapter): TreeItem {
        return element;
    }

    getChildren(element?: BasicTreeItem): Thenable&lt;BasicTreeItem[]&gt; {
        if (element instanceof Chapter) {
            return getChapterLinksItems(element.nestedLinks); //root element child (link)
        }
        return getChaptersItems(); //root element (chapter)
    }
}</pre>



<p>Also, we need a <a class="notion-link-token notion-enable-hover" href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/services/treeItemsService.ts" target="_blank" rel="noopener noreferrer" data-token-index="1" data-reactroot=""><span class="link-annotation-unknown-block-id-853608805">treeItemService</span></a> that will fetch data from the config hosted on GitHub Pages and convert it into <span class="notion-enable-hover" spellcheck="false" data-token-index="3" data-reactroot="">TreeItems</span>.</p>



<pre class="crayon-plain-tag">export const getChapterLinksItems = async (nestedLinks: LinkNode[]): Promise&lt;TreeItem[]&gt; =&gt; {
	const links: Link[] = convertLinksItems(nestedLinks);
	return Promise.resolve(links);
};

export const getChaptersItems = async (): Promise&lt;Chapter[]&gt; =&gt; {
	try {
		const config = await getDocumentationConfig(); //fetching documentation config
		return Promise.resolve(convertChaptersItems(config.root));
	} catch (e) {
		window.showErrorMessage(&quot;Error occurred while fetching documentation config ?&quot;);
		return Promise.resolve([]);
	}
};

const convertChaptersItems = (chapters: ChapterNode[]): Chapter[] =&gt;
	chapters.map(
		(chapter) =&gt;
			new Chapter( //extends TreeItem
				chapter.title,
				chapter.link,
				chapter.links,
				TreeItemCollapsibleState.Collapsed //means that this tree item can have children
			)
	);

const convertLinksItems = (links: LinkNode[]): Link[] =&gt;
	links.map((link) =&gt; 
		new Link( //extends TreeItem
			link.title, 
			link.link, 
			TreeItemCollapsibleState.None //means that this tree item can't have children
		)
	);</pre>



<p>The third step is to register the above data provider to your view in the extension.ts. This can be done in the following way:</p>



<pre class="crayon-plain-tag">export async function activate(context: ExtensionContext) {
	const documentationProvider = new DocumentationProvider();
	window.registerTreeDataProvider('documentation-browser', documentationProvider); //bind documentation-browser to documentationProvider
}</pre>



<p>extension.ts is the main file of the extension. It contains a view to provider bindings and commands registrations .</p>
<p>Here is the result? :</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="342" height="144" src="https://binary-studio.com/wp-content/uploads/2022/01/Untitled-1.png" alt="VS Code extension" class="wp-image-25044" srcset="https://binary-studio.com/wp-content/uploads/2022/01/Untitled-1.png 342w, https://binary-studio.com/wp-content/uploads/2022/01/Untitled-1-300x126.png 300w" sizes="(max-width: 342px) 100vw, 342px" /></figure></div>



<p>Finally, let's add controls to be able to open listed links in the browser.</p>
<p>To implement this, you should follow three steps: contribute the command in your <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/package.json">package.json</a></code> , implement business logic in the <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/providers/DocumentationProvider.ts">DocumentationProvider</a></code> , and bind the handler with the command in the <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/extension.ts">extension.ts</a></code>.</p>
<p>First, you have to contribute a command and set its place using the&nbsp;<a href="https://code.visualstudio.com/api/references/contribution-points#contributes.commands">contributes.commands</a> and <a href="https://code.visualstudio.com/api/references/contribution-points#contributes.menus">contributes.menus</a> Contribution Points in <code><a href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/package.json">package.json</a></code>.</p>



<pre class="crayon-plain-tag">&quot;commands&quot;: [ // creating command
	{ 
		&quot;command&quot;: &quot;documentation-browser.openLink&quot;, //command name
		&quot;title&quot;: &quot;Go to documentation&quot;,
		&quot;icon&quot;: {
			&quot;light&quot;: &quot;resources/light/goByLink.svg&quot;, //icon for the control (light theame)
			&quot;dark&quot;: &quot;resources/dark/goByLink.svg&quot; //icon for the control (dark theame)
		}
	}
],
&quot;menus&quot;: { // setting a place for created command
	&quot;view/item/context&quot;: [
		{
			&quot;command&quot;: &quot;documentation-browser.openLink&quot;, //related command name
			&quot;when&quot;: &quot;view == documentation-browser&quot;, //will be visible only on documentation-browser view
			&quot;group&quot;: &quot;inline&quot;
		}
	]
}</pre>



<p>Next, let's create a method to handle this command in <a class="notion-link-token notion-enable-hover" href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/providers/DocumentationProvider.ts" target="_blank" rel="noopener noreferrer" data-token-index="1" data-reactroot=""><span class="link-annotation-unknown-block-id--776685493">DocumentationProvider</span></a> :</p>



<pre class="crayon-plain-tag">openExternalURI(link: string) {
      env.openExternal(Uri.parse(link)); // opens link in your browser
}</pre>



<p>Finally, you have to bind your command and a handler in <a class="notion-link-token notion-enable-hover" href="https://github.com/MaksymSlobodianyk/vscode-extension-tree-view-example/blob/main/src/extension.ts" target="_blank" rel="noopener noreferrer" data-token-index="1" data-reactroot=""><span class="link-annotation-unknown-block-id-1212681834">extension.ts</span></a>.</p>



<pre class="crayon-plain-tag">export async function activate(context: ExtensionContext) {
	...
	registerCommands(documentationProvider);
}

const registerCommands = (documentationProvider: DocumentationProvider) =&amp;gt; {
	commands.registerCommand('documentation-browser.openLink', node =&amp;gt;
		documentationProvider.openExternalURI(node.link)
	)
}</pre>



<p>As result, we are able to open every item link by clicking the control on the item.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="377" height="158" src="https://binary-studio.com/wp-content/uploads/2022/01/Peek_2021-11-29_12-08.gif" alt="" class="wp-image-25029"/></figure></div>



<p>Now that you have a basic idea of how an extension works under the hood, let me show you how 0.1.0 (the MVP) looked like.</p>
<p>I implemented six main features:</p>
<ul>
<li>Listing of installed plugins and their current versions;</li>
<li>Ability to open the certain plugin in a new VS Code or Sublime window;</li>
<li>Ability to open a folder that contains all plugins in a new VS Code or Sublime window;</li>
<li>Ability to update all outdated plugins by a single button;</li>
<li>Highlighting outdated plugins.</li>
</ul>



<div class="wp-block-image"><figure class="aligncenter size-large is-resized"><img src="https://binary-studio.com/wp-content/uploads/2022/01/image1.gif" alt="" class="wp-image-25030" width="403" height="484"/></figure></div>



<p>As you might have guessed, plugins were listed in the <a class="notion-link-token notion-enable-hover" href="https://code.visualstudio.com/api/extension-guides/tree-view" target="_blank" rel="noopener noreferrer" data-token-index="1" data-reactroot=""><span class="link-annotation-unknown-block-id-1213516467">Tree view</span></a>. I added a vendor logo as a tree item icon to simplify the visual search of the needed plugin. Also, VS Code provides a built-in highlighting and filtering of items that have entered symbols in their title.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="612" height="302" src="https://binary-studio.com/wp-content/uploads/2022/01/image5.gif" alt="" class="wp-image-25031"/></figure></div>



<p>Controls that are related to a single plugin were placed on each plugin item and ones related to all plugins were placed on the top of the plugin's browser view. Also, I added a bunch of settings that allows each developer to leave only controls that they really needed. As you can see, Sublime related buttons are hidden on the description map illustration.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="1024" height="430" src="https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description-1024x430.png" alt="" class="wp-image-25032" srcset="https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description-1024x430.png 1024w, https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description-300x126.png 300w, https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description-768x322.png 768w, https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description-1536x644.png 1536w, https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description-624x262.png 624w, https://binary-studio.com/wp-content/uploads/2022/01/v010_fm_description.png 2000w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure></div>



<p>The prototype allowed me to check whether it is convenient to use these controls placed in such a way or not.</p>



<h2><strong>How does it look like now?</strong></h2>
<p>MVP solved many pains and proved that it's pretty convenient to manage plugins in a tree view, but we still had some pains to solve, so I continued releasing new versions. Now, 5 months after the MVP, the extension evolved to version 0.4.1. Many significant features have been released and some colleagues have joined the development.</p>
<p>Unfortunately, VS code documentation is not really filled with examples of complex features and VS code API capabilities, so the next step that helped me a lot in my development journey was examining the code base of other extensions to find out how they implemented any of their features. Lots of pretty popular extensions keep repositories public, like <a href="https://github.com/Axosoft/vscode-gitlens">GitLens</a>. There are also two important documentation chapters: VS Code API <a href="https://code.visualstudio.com/api/references/vscode-api">reference</a> - you can always refer to it in case you need to find a way how to interact with IDE or OS features from your extension. Contribution points <a href="https://code.visualstudio.com/api/references/contribution-points">reference</a> - it contains documentation on how to set up extension appearance, key bindings, controls, configs, etc.</p>
<p>By this time, we’ve added more functionality to plugins items, so you have the possibility to view all forks, branches of forks, opened pull requests, branches, and tags of each plugin repo. Moreover, you can install plugins from any of these sources. Also, using an OctoCat button on a fork item you can do a git clone of the forked repo. In other words, just fork a repo on the GitHub site then switch to VS Code, and with a single click replace the installed plugin with the ready for development cloned one.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="1024" height="355" src="https://binary-studio.com/wp-content/uploads/2022/01/ver_description-1024x355.png" alt="" class="wp-image-25033" srcset="https://binary-studio.com/wp-content/uploads/2022/01/ver_description-1024x355.png 1024w, https://binary-studio.com/wp-content/uploads/2022/01/ver_description-300x104.png 300w, https://binary-studio.com/wp-content/uploads/2022/01/ver_description-768x266.png 768w, https://binary-studio.com/wp-content/uploads/2022/01/ver_description-1536x532.png 1536w, https://binary-studio.com/wp-content/uploads/2022/01/ver_description-624x216.png 624w, https://binary-studio.com/wp-content/uploads/2022/01/ver_description.png 1767w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure></div>



<p>After solving the known pains of the team I thought about what else could be integrated into the extension. Recently, we started the development of in-project documentation and I decided to add it as a documentation browser. It’s a convenient way to collect and group important project documentation links. You can easily add new chapters and links or edit existing ones just by modifying the JSON config which is hosted with GitHub pages. Your changes will be instantly visible for every extension user.</p>
<p>Here is how documentation browser looks like:</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="1024" height="239" src="https://binary-studio.com/wp-content/uploads/2022/01/doc_description-1024x239.png" alt="" class="wp-image-25034" srcset="https://binary-studio.com/wp-content/uploads/2022/01/doc_description-1024x239.png 1024w, https://binary-studio.com/wp-content/uploads/2022/01/doc_description-300x70.png 300w, https://binary-studio.com/wp-content/uploads/2022/01/doc_description-768x179.png 768w, https://binary-studio.com/wp-content/uploads/2022/01/doc_description-1536x358.png 1536w, https://binary-studio.com/wp-content/uploads/2022/01/doc_description-624x145.png 624w, https://binary-studio.com/wp-content/uploads/2022/01/doc_description.png 1767w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure></div>



<p>We used many VS Code API features to cover over needs, but the most common thing the user faces are notifications. We use them to notify developers about, errors, task progress, and to ask some actions which could be required during plugins update or clone processes.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="814" height="320" src="https://binary-studio.com/wp-content/uploads/2022/01/notifications.png" alt="" class="wp-image-25035" srcset="https://binary-studio.com/wp-content/uploads/2022/01/notifications.png 814w, https://binary-studio.com/wp-content/uploads/2022/01/notifications-300x118.png 300w, https://binary-studio.com/wp-content/uploads/2022/01/notifications-768x302.png 768w, https://binary-studio.com/wp-content/uploads/2022/01/notifications-624x245.png 624w" sizes="(max-width: 814px) 100vw, 814px" /></figure></div>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="1024" height="355" src="https://binary-studio.com/wp-content/uploads/2022/01/v040_fm-1024x355.png" alt="" class="wp-image-25036" srcset="https://binary-studio.com/wp-content/uploads/2022/01/v040_fm-1024x355.png 1024w, https://binary-studio.com/wp-content/uploads/2022/01/v040_fm-300x104.png 300w, https://binary-studio.com/wp-content/uploads/2022/01/v040_fm-768x266.png 768w, https://binary-studio.com/wp-content/uploads/2022/01/v040_fm-1536x532.png 1536w, https://binary-studio.com/wp-content/uploads/2022/01/v040_fm-624x216.png 624w, https://binary-studio.com/wp-content/uploads/2022/01/v040_fm.png 1922w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure></div>



<h2>Is it worth it?</h2>
<p>Absolutely, yes! Using the extension, we improved our plugins management and development experience quite a bit. Moreover, we are on the way to converting the plugins management extension to an entire project hub that will contain all the information and tools required for development. By the way, the documentation browser is the first milestone of this trip.</p>
<p>It seems to me that if you develop a long-term support product with some project-specific frequent actions that could be automatized, VS Code extension may be a good way to implement this. Also, as in our team's case, an extension development initiative can spread over the team and result in a team PET project.</p>
<p>I hope this blog post provides you with some ideas on how such an extension could improve your work experience. Just keep in mind that VS Code extension is an extremely powerful tool, which is mostly just limited by your needs and imagination!</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2022/01/18/developing-vs-code-extension-to-resolve-your-dev-team-pains/">Developing VS Code extension to resolve your dev team pains</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2022/01/18/developing-vs-code-extension-to-resolve-your-dev-team-pains/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Lint your project with Github Actions</title>
		<link>https://binary-studio.com/2021/12/21/lint-your-project-with-github-actions/</link>
					<comments>https://binary-studio.com/2021/12/21/lint-your-project-with-github-actions/#respond</comments>
		
		<dc:creator><![CDATA[Vladyslav Zubko]]></dc:creator>
		<pubDate>Tue, 21 Dec 2021 16:38:51 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=20327</guid>

					<description><![CDATA[<p>Init Simple project Let's set up a simple project to see how it works! [crayon-631f4f0e1bae0573794698/] Install ESLint. ESLint is a tool for identifying and reporting on patterns found in JavaScript code. [crayon-631f4f0e1bae7722787437/] ESLint configuration file example: [crayon-631f4f0e1bae9727999979/] Also, do not forget to update the scripts section in the package.json. [crayon-631f4f0e1baeb766640380/] Github&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/12/21/lint-your-project-with-github-actions/">Lint your project with Github Actions</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2>Init Simple project</h2>
<p>Let's set up a simple project to see how it works!</p>
<pre class="crayon-plain-tag">npm init -y</pre>
<p>Install <a href="https://eslint.org/">ESLint</a>. ESLint is a tool for identifying and reporting on patterns found in JavaScript code.</p>
<pre class="crayon-plain-tag">npm install eslint -DE</pre>
<p>ESLint <a href="https://eslint.org/docs/user-guide/configuring/configuration-files">configuration file</a> example:</p>
<pre class="crayon-plain-tag"># .eslintrc.yml
 
env:
es2021: true
browser: true
 
extends:
  - eslint:recommended
 
parserOptions:
ecmaVersion: 2021
sourceType: module</pre>
<p>Also, do not forget to update the scripts section in the package.json.</p>
<pre class="crayon-plain-tag">// scripts in package.json

{
 "scripts": {
 "lint:js": "eslint src/**/*.js",
 "lint": "npm run lint:js"
 }
}</pre>
<h2>Github Actions in general</h2>
<p>Github Actions are commands for github to run some code every time an event occurs (Push, Merge, PR and etc.). The code runs on github virtual machines.</p>
<p>What does this code do? Anything. It allows you to automate things necessary for your development process: run tests/lints, deployment, and notify people.</p>
<p>Github Actions give a nice and free CI/CD and also allow you to create a flexible and easily configurable system for development.</p>
<p>Let's look at a simple example — for each push to one of the environment branches (development, staging, production) we will run linting (example will use <span style="color: #000000;"><a style="color: #000000;" href="https://binary-studio.com/2021/08/04/js-and-everyday-data-structures/">JavaScript</a></span>).</p>
<p>Action Example:</p>
<pre class="crayon-plain-tag"># .github/workflows/lint.yml

name: Lint # name of the action (displayed in the github interface)

on: # event list
pull_request: # on a pull request to each of these branches
branches:
  - development
  - staging
  - production

env: # environment variables (available in any part of the action)
  NODE_VERSION: 16

jobs: # list of things to do
  linting:
    name: Linting # job name (unique id)
    runs-on: ubuntu-latest # on which machine to run
    steps: # list of steps
      - name: Install NodeJS
        uses: actions/setup-node@v2
        with:
          node-version: ${{ env.NODE_VERSION }}

      - name: Code Checkout
        uses: actions/checkout@v2

      - name: Install Dependencies
        run: npm ci

      - name: Code Linting
        run: npm run lint</pre>
<h2>Steps syntax</h2>
<ul>
<li><strong><code md-src-pos="2244..2250">name</code></strong> — needed to be displayed in the github interface;</li>
<li><strong><code md-src-pos="2307..2313">uses</code></strong> — specify the name of custom actions if we want to use it. You can find many ready-made actions in the <a href="https://github.com/marketplace">marketplace</a>;</li>
<li><strong><code md-src-pos="2470..2476">with</code></strong> — parameters for custom actions;</li>
<li><strong><code md-src-pos="2516..2521">run</code></strong> — runs commands in the <code md-src-pos="2547..2554">shell</code>. <em>It is forbidden to use a shell commands with custom actions.</em></li>
</ul>
<p>That's it, we took apart a small but useful example of the github action!</p>
<p>In the github interface, the runs will look like this:</p>
<p> </p>
<p style="text-align: center;"><img class="alignnone wp-image-20350 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image7.jpg" alt="" width="1113" height="408" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image7.jpg 1113w, https://binary-studio.com/wp-content/uploads/2021/12/image7-300x110.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/12/image7-1024x375.jpg 1024w, https://binary-studio.com/wp-content/uploads/2021/12/image7-768x282.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/12/image7-624x229.jpg 624w" sizes="(max-width: 1113px) 100vw, 1113px" /></p>
<p style="text-align: center;"><em>Run History</em></p>
<p><img class="aligncenter wp-image-20348 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image5.jpg" alt="" width="1436" height="410" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image5.jpg 1436w, https://binary-studio.com/wp-content/uploads/2021/12/image5-300x86.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/12/image5-1024x292.jpg 1024w, https://binary-studio.com/wp-content/uploads/2021/12/image5-768x219.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/12/image5-624x178.jpg 624w" sizes="(max-width: 1436px) 100vw, 1436px" /></p>
<p style="text-align: center;"><em>Inside Each Run</em></p>
<h2>Branch protection</h2>
<p>To prohibit merging a pull request when linting fails, go to the repository settings and set the merge rules for the branch you want. To do this we need to check the <em>Require status checks to pass before merging</em> checkbox and select the checks we need. In our case, this is <em>Linting</em> (the name is taken from the action config).</p>
<p><img class="alignnone wp-image-20349 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image6.jpg" alt="" width="1102" height="596" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image6.jpg 1102w, https://binary-studio.com/wp-content/uploads/2021/12/image6-300x162.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/12/image6-1024x554.jpg 1024w, https://binary-studio.com/wp-content/uploads/2021/12/image6-768x415.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/12/image6-624x337.jpg 624w" sizes="(max-width: 1102px) 100vw, 1102px" /></p>
<p>Now in each pull request to the branch we need we will see the result of the action. If all is well, the action will be passed:</p>
<p><img class="alignnone wp-image-20347 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image4.jpg" alt="" width="830" height="249" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image4.jpg 830w, https://binary-studio.com/wp-content/uploads/2021/12/image4-300x90.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/12/image4-768x230.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/12/image4-624x187.jpg 624w" sizes="(max-width: 830px) 100vw, 830px" /></p>
<p>But if we broke something the action will fail:</p>
<p><img class="alignnone wp-image-20344 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image1.jpg" alt="" width="819" height="232" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image1.jpg 819w, https://binary-studio.com/wp-content/uploads/2021/12/image1-300x85.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/12/image1-768x218.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/12/image1-624x177.jpg 624w" sizes="(max-width: 819px) 100vw, 819px" /></p>
<p>Inside each action we can find out what exactly went wrong. For example, here the action tells us that there are unused variables in the code:</p>
<p><img class="alignnone wp-image-20346 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image3-e1640165659624.jpg" alt="" width="1111" height="207" /></p>
<h2>Linting other files</h2>
<p>For now, we only check the format of the <code md-src-pos="3524..3528">js</code> files. It is not very good. Attention should be paid not only to <code md-src-pos="3594..3598">js</code> files, as there are usually other file formats that developers pay less attention to. Let's fix this and add additional linters to protect our code.</p>
<h2>Style Lint</h2>
<p><a href="https://stylelint.io/">Stylelint</a> is a mighty, modern linter that helps you avoid errors and enforce conventions in your styles.</p>
<p>I use a simple example in which I just extend the config from the recommended. But even with this couple of lines we will protect our styles.</p>
<p>Stylelint supports a huge number of configuration options. Be sure to check the <a href="https://stylelint.io/user-guide/configure">documentation</a> to find the rules that fit your project.</p>
<pre class="crayon-plain-tag">npm install stylelint stylelint-config-standard -DE</pre>
<p>Stylelint <a href="https://stylelint.io/user-guide/configure">configuration file</a> example:</p>
<pre class="crayon-plain-tag"># .stylelintrc.yml
 
extends:
  - stylelint-config-standard</pre>
<p>Updated <code md-src-pos="4444..4458">package.json</code>:</p>
<p>// scripts in package.json</p>
<pre class="crayon-plain-tag">{
 "scripts": {
 "lint:css": "stylelint src/**/*.css",
 "lint:js": "eslint src/**/*.js",
 "lint": "npm run lint:css &amp;&amp; npm run lint:js"
 }
}</pre>
<h2>EditorConfig Lint</h2>
<p><a href="https://editorconfig.org/">EditorConfig</a> helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.</p>
<pre class="crayon-plain-tag">npm install editorconfig-checker -DE</pre>
<p>EditorConfig <a href="https://editorconfig.org/#example-file">configuration file</a> example:</p>
<pre class="crayon-plain-tag"># .editorconfig

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8</pre>
<p>Updated package.json:</p>
<pre class="crayon-plain-tag">// scripts in package.json

{
 "scripts": {
 "lint:editorconfig": "editorconfig-checker",
 "lint:css": "stylelint src/**/*.css",
 "lint:js": "eslint src/**/*.js",
 "lint": "npm run lint:editorconfig &amp;&amp; npm run lint:css &amp;&amp; npm run  lint:js"
 }
}</pre>
<h2>Ls Lint</h2>
<p><a href="https://ls-lint.org/">Ls-lint</a> — file and directory name linter. Bring some structure to your project directories.</p>
<pre class="crayon-plain-tag">npm install @ls-lint/ls-lint -DE</pre>
<p>Ls Lint <a href="https://ls-lint.org/1.x/configuration/the-basics.html">configuration file</a> example:</p>
<pre class="crayon-plain-tag"># .ls-lint.yml
 
ls:
  .dir: kebab-case
  .js: kebab-case
  .css: regex:([.a-z]*)([-.][a-z]+)*
 
ignore:
  - node_modules
  - .git</pre>
<p>Updated <code md-src-pos="5850..5864">package.json</code>:</p>
<p>// scripts in package.json</p>
<pre class="crayon-plain-tag">{
 "scripts": {
 "lint:ls": "ls-lint",
 "lint:editorconfig": "editorconfig-checker",
 "lint:css": "stylelint src/**/*.css",
 "lint:js": "eslint src/**/*.js",
 "lint": "npm run lint:ls &amp;&amp; npm run lint:editorconfig &amp;&amp; npm run  lint:css &amp;&amp; npm run lint:js"
 }
}</pre>
<p>Now <strong>4</strong> linters will run for each pull request. I hope you and your team will follow and improve the linters configs. And you will always see the linter result without errors:</p>
<p><img class="alignnone wp-image-20345 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image2.jpg" alt="" width="1043" height="428" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image2.jpg 1043w, https://binary-studio.com/wp-content/uploads/2021/12/image2-300x123.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/12/image2-1024x420.jpg 1024w, https://binary-studio.com/wp-content/uploads/2021/12/image2-768x315.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/12/image2-624x256.jpg 624w" sizes="(max-width: 1043px) 100vw, 1043px" /></p>
<h2>Pricing</h2>
<p>Github actions are not free. Now the free plan gives ~2000 minutes. Usually this is enough for small and medium projects.</p>
<p>You can always find up-to-date information on the use-plan <a href="https://github.com/pricing">here</a>.</p>
<h2>Conclusions</h2>
<p>You know the basics of Github Actions now, and I hope this article clarifies all of the basic principles.</p>
<p>This example does not cover all the opportunities. Github has a wonderful <a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions">documentation</a>, which describes many interesting things!</p>
<p>Linting code is just an example. Everything can be automated.</p>
<p>Some examples:</p>
<ul>
<li>Running tests on each pull request;</li>
<li>Deploying on push to production branch;</li>
<li><a href="https://prettier.io/">Prettify</a> your code before merging;</li>
<li>Publishing packages;</li>
<li>Sending notifications on each pull request/issue, etc.</li>
</ul>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/12/21/lint-your-project-with-github-actions/">Lint your project with Github Actions</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2021/12/21/lint-your-project-with-github-actions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Binary Studio Recognised as Top 1000 Service Providers in 2021</title>
		<link>https://binary-studio.com/2021/12/06/binary-studio-recognised-as-top-1000-service-providers/</link>
					<comments>https://binary-studio.com/2021/12/06/binary-studio-recognised-as-top-1000-service-providers/#respond</comments>
		
		<dc:creator><![CDATA[Daryna Mishchuk]]></dc:creator>
		<pubDate>Mon, 06 Dec 2021 10:00:08 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=20260</guid>

					<description><![CDATA[<p>Binary Studio is proud to announce that we've been named a Top 1000 company by Clutch, a leading B2B ratings, and reviews firm.  Clutch is a B2B review and rating platform that conducts extensive research on companies and ranks them based on quality services, customer feedback, ratings and reviews, project engagement&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/12/06/binary-studio-recognised-as-top-1000-service-providers/">Binary Studio Recognised as Top 1000 Service Providers in 2021</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><span style="font-weight: 400;">Binary Studio is proud to announce that we've been named a Top 1000 company by Clutch, a leading B2B ratings, and reviews firm. </span></p>
<p><span style="font-weight: 400;">Clutch is a B2B review and rating platform that conducts extensive research on companies and ranks them based on quality services, customer feedback, ratings and reviews, project engagement methodologies, the scope of the clients served, their market presence, and brand reputation. Every year, the site holds an awards cycle to celebrate and highlight the highest-performing companies from different industries and locations worldwide.</span></p>
<p><span style="font-weight: 400;">At Binary Studio, client satisfaction is our priority. We work hard to fulfill our clients' needs and build </span><span style="color: #ff9900;"><a style="color: #ff9900;" href="https://binary-studio.com/custom-software-development/"><span style="font-weight: 400;">high-quality solutions</span></a></span><span style="font-weight: 400;"> that exceed their expectations. </span></p>
<p><span style="font-weight: 400;">We would like to thank our esteemed clients for helping us achieve our goals and getting us this prestigious award! We couldn't have gotten this far without their trust and support. Their excellent reviews also continue to ignite our passion for our work. Their genuine appreciation of our efforts touches us, and we want to assure everyone that we will keep doing our best. Here's one of the latest perfect scores a client gave us:</span></p>
<p><img class="alignnone wp-image-20266 size-full" src="https://binary-studio.com/wp-content/uploads/2021/12/image1.png" alt="" width="1716" height="946" srcset="https://binary-studio.com/wp-content/uploads/2021/12/image1.png 1716w, https://binary-studio.com/wp-content/uploads/2021/12/image1-300x165.png 300w, https://binary-studio.com/wp-content/uploads/2021/12/image1-1024x565.png 1024w, https://binary-studio.com/wp-content/uploads/2021/12/image1-768x423.png 768w, https://binary-studio.com/wp-content/uploads/2021/12/image1-1536x847.png 1536w, https://binary-studio.com/wp-content/uploads/2021/12/image1-624x344.png 624w" sizes="(max-width: 1716px) 100vw, 1716px" /></p>
<p><span style="font-weight: 400;">Visit our </span><a href="https://clutch.co/profile/binary-studio"><span style="font-weight: 400;">Clutch page</span></a><span style="font-weight: 400;"> to learn more about what our clients are saying about us.</span></p>
<p><span style="font-weight: 400;">Looking for a team that can elevate your business? Take the first step forward and talk to our experts! Thanks to our rigorous Academy at Binary Studio, we recruit the top 0.5% of software specialists in Ukraine and other CEE countries. Want to know more? </span><span style="color: #ff9900;"><a style="color: #ff9900;" href="https://binary-studio.com/contact-us/"><span style="font-weight: 400;">Drop us a line</span></a></span><span style="font-weight: 400;">, and let's talk about how we can help your business transform.</span></p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/12/06/binary-studio-recognised-as-top-1000-service-providers/">Binary Studio Recognised as Top 1000 Service Providers in 2021</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2021/12/06/binary-studio-recognised-as-top-1000-service-providers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>IDOR prevention in ASP.NET Core</title>
		<link>https://binary-studio.com/2021/11/01/idor-prevention-in-asp-net-core/</link>
					<comments>https://binary-studio.com/2021/11/01/idor-prevention-in-asp-net-core/#respond</comments>
		
		<dc:creator><![CDATA[Yurii Palaida]]></dc:creator>
		<pubDate>Mon, 01 Nov 2021 13:01:00 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[IDOR prevention]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=20136</guid>

					<description><![CDATA[<p>Imagine you start a promo campaign to say thank you to your most loyal users. You send them links for activating special conditions for using your service. Soon you notice that instead of getting a discount for one month, they grant themselves almost lifetime access. You close the campaign, making angry&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/11/01/idor-prevention-in-asp-net-core/">IDOR prevention in ASP.NET Core</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><span style="font-weight: 400;">Imagine you start a promo campaign to say thank you to your most loyal users. You send them links for activating special conditions for using your service. Soon you notice that instead of getting a discount for one month, they grant themselves almost lifetime access.</span></p>
<p><span style="font-weight: 400;">You close the campaign, making angry not-so-fast but still loyal users, and start looking for a source of the issue. It turns out that the problem was with the promo codes.</span></p>
<p><span style="font-weight: 400;">Every user receives a link that looks something like this: “</span><a href="https://service.com/promo?code=2"><span style="font-weight: 400;">https://service.com/promo?code=2</span></a><span style="font-weight: 400;">”. Smart (but still loyal) users try their luck with code #3, then #4, and at some time they get to their lucky number with a lot of subsequent ones. Pretty obvious, but still a problem.</span></p>
<p><span style="font-weight: 400;">Or it may be another issue with users getting access to resources they are not supposed to reach. For example, the photo of your favorite puppy can be found by this link “</span><a href="https://photos.com/1001"><span style="font-weight: 400;">https://photos.com/1001</span></a><span style="font-weight: 400;">”. But you can’t deny that it’s so tempting to try what is in “</span><a href="https://photos.com/1002"><span style="font-weight: 400;">https://photos.com/1002</span></a><span style="font-weight: 400;">” and so on. </span></p>
<p><span style="font-weight: 400;">There are a couple of ways to deal with this issue:</span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Basic authorization with access control policies, defining what resource each user can get (the best solution for the second scenario with retrieving other users’ photos)</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Input validation (checking what exactly the user wants to get)</span></li>
</ul>
<p><span style="font-weight: 400;">Of course, all these scenarios may sound trivial. But websites nowadays still suffer from different vulnerabilities, and there is one more solution to deal with them - insecure direct object reference prevention.</span></p>
<p><span style="font-weight: 400;">The main idea is not to expose the identifiers of the resources for the end-user. There will be “incomprehensible garbage” that only your backend can deal with, getting it from requests, routes, or query parameters. For example, “https://photos.com/gfdkj4t34-g0gd _V” instead of “</span><a href="https://photos.com/1001"><span style="font-weight: 400;">https://photos.com/1001</span></a><span style="font-weight: 400;">”. We’ll implement this in a basic .NET Web API application that will be able to encrypt all outcoming IDs and decrypt incoming ones.</span></p>
<h2>One class to rule them all</h2>
<p><span style="font-weight: 400;">First, we need one class that will represent this encrypted value. </span></p>
<p><span style="font-weight: 400;">It’s important since we don’t want to do encryption manually every time. We could also make middleware that would encrypt all values of some specific type, but that is a very inflexible solution. For example, if IDs in your system are integers, there is no way for returning all of them as encrypted.</span></p>
<p><span style="font-weight: 400;">Probably, it’ll be easier to represent IDs as Guid (UUID) values, but imagine that at some point, you’d need to return some decrypted value. It creates difficulties.</span></p>
<p><span style="font-weight: 400;">Instead of adding a separate class, it’s also possible to make an attribute, but that’s not convenient. So we’ll go with a separate class.</span></p>
<p><span style="font-weight: 400;">Thinking ahead, we can make this class generic to encrypt data of any type: from string and integers to Guids. But if you’re 100% sure that it’ll be used just for your IDs, then make it strongly-typed.</span></p>
<p><span style="font-weight: 400;">This class won’t store any complex logic. We need it only for storing data about the identifier. It’s going to have one property with the id itself that we can access directly and a constructor for creating new instances.</span></p>
<pre class="crayon-plain-tag">public class Id&lt;T&gt;
{
    public T Value { get; }

    public Id(T value)
    {
        Value = value;
    }
}</pre>
<p><span style="font-weight: 400;">From now on we can use this type for our identifiers. For example,</span></p>
<pre class="crayon-plain-tag">public class Entity
{
    public Id&lt;Guid&gt; Id { get; set; }
    public string name { get; set; }
}</pre>
<p><span style="font-weight: 400;">If you do decide to make this class strongly-typed and use it only for the IDs (that are of Guid type), then it will be like this:</span></p>
<pre class="crayon-plain-tag">public class Id
{
    public Guid Value { get; }

    public Id(Guid value)
    {
        Value = value;
    }
}</pre>
<h2><span style="font-weight: 400;">Encryptor</span></h2>
<p><span style="font-weight: 400;">As for the encryption, we can implement it ourselves or use existing libraries. Since the main idea behind this material is to show a practical implementation of indirect object reference prevention, there is no sense in reinventing the wheel. I’m using NETCore.Encrypt (https://www.nuget.org/packages/NETCore.Encrypt).</span></p>
<p><i><span style="font-weight: 400;">Though there may be situations when you can consider creating your solution. For example, if you go with Guids, you can significantly reduce the length of your final value. Since AES encryption works with blocks of 128 bits and one Guid is exactly 128 bits, you can get rid of paddings, which would result in a much shorter encrypted value (though no padding may reduce security also). But it’s just a point for consideration.</span></i></p>
<p><span style="font-weight: 400;">So, our encryption class can be as simple as this:</span></p>
<pre class="crayon-plain-tag">public interface IEncryptor
{
    public string Encrypt(object o);
    public string Decrypt(string o);
}

public class Encryptor : IEncryptor
{
    private readonly string _key;
    private readonly string _iv;

    public Encryption(IConfiguration configuration)
    {
        var section = configuration.GetSection("Encryption");
        _key = section.GetValue&lt;string&gt;("Key");
        _iv = section.GetValue&lt;string&gt;("IV");
    }
    public string Encrypt(object data)
    {
        return EncryptProvider.AESEncrypt(data.ToString(), _key, _iv);
    }

    public string Decrypt(string data)
    {
        return EncryptProvider.AESDecrypt(data, _key, _iv);
    }
}</pre>
<p><span style="font-weight: 400;">I skip different checks for the sake of brevity and leave only the essential stuff, but it’s important to foresee different scenarios.</span></p>
<p><span style="font-weight: 400;">We’ll store the key and the initialization vector needed for AES encryption to work in the appsettings.json file, but they can reside anywhere else.</span></p>
<pre class="crayon-plain-tag">{
  "Encryption": {
    "Key": "U7KzmRT1Y69VkbqK7zLf7m64aPaXiS9m",
    "IV": "2P2AEIuWfStFT7Yy"
  }
}</pre>
<p><span style="font-weight: 400;">The only thing left is to register this service as a singleton and we can use its interface to encrypt and decrypt data.</span></p>
<pre class="crayon-plain-tag">public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton&lt;IEncryptor, Encryptor&gt;();
}</pre>
<p><span style="font-weight: 400;">In this case, we will be able to use this service anywhere but still have to call it manually. There is yet an opportunity to automate conversion, for which we need to use JSON converters.</span></p>
<h2><span style="font-weight: 400;">JSON converter</span></h2>
<p><span style="font-weight: 400;">In ASP.NET Core we can create custom JSON converters with defined logic for reading and writing values in a specific format.</span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">We want our Id&lt;Guid&gt; be converted into an encrypted string while serializing.</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">And we need to deserialize an encrypted string, decrypt it and save the value in Id&lt;Guid&gt; object.</span></li>
</ul>
<pre class="crayon-plain-tag">public class GuidConverter : JsonConverter&lt;Id&lt;Guid&gt;&gt;
{
    private readonly IEncryptor _encryptor;

    public Converter(IEncryptor encryptor)
    {
        _encryptor = encryptor;
    }

    public override Id&lt;Guid&gt; Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        object decryptedGuid = _encryptor.Decrypt(reader.GetString());
        Guid.TryParse(decryptedGuid.ToString(), out Guid value);
        return new Id&lt;Guid&gt;(value);
    }

    public override void Write(Utf8JsonWriter writer, Id&lt;Guid&gt; value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(_encryptor.Encrypt(value.Value));
    }
}</pre>
<p><span style="font-weight: 400;">Microsoft suggests using factories to extend JSON converters but for simplicity let's use a converter directly.</span></p>
<p><span style="font-weight: 400;">In a Read method, we get a string value from the reader, decrypt it, convert it to Guid and return it in the form of an Id&lt;Guid&gt; object. You can imagine how many issues can happen in this step. So it makes sense to make this method generic and add different checks.</span></p>
<p><span style="font-weight: 400;">It’s even simpler inside a Write method: encrypt a value and write it into a string. And that’s it.</span></p>
<p><span style="font-weight: 400;">Next step, we need to register that converter:</span></p>
<pre class="crayon-plain-tag">public void ConfigureServices(IServiceCollection services)
{
    var encryptor = new Encryptor(Configuration);
    services.AddControllers().AddJsonOptions(x =&gt; 
        x.JsonSerializerOptions.Converters.Add(new Converter(encryptor)));
}</pre>
<p><span style="font-weight: 400;">And now it’ll automatically handle serializing an Id&lt;Guid&gt; object into an encrypted string and create an Id&lt;Guid&gt; object from an encrypted string.</span></p>
<p><span style="font-weight: 400;">Note:</span></p>
<p><i><span style="font-weight: 400;">There is one more point for creating your implementation of encryption, since, for example, the chosen library generates a string in base64 format, which includes symbols like “\” and “+”. It means that after encryption, you also need to encode the output. It will make it usable not only in the body of the response but also as a part of the route or a query parameter.</span></i></p>
<p><i><span style="font-weight: 400;">And if you make encryption yourself, it’s quite easy to convert encrypted bytes into the url-safe format of base64, where “/” and “+” are substituted by “-” and “_”.</span></i></p>
<h2><span style="font-weight: 400;">IDOR prevention in action</span></h2>
<p><span style="font-weight: 400;">The last step is to see how it all works in practice. For example, we have this basic controller.</span></p>
<pre class="crayon-plain-tag">[Route("api/[controller]")]
[ApiController]
public class EntitiesController : ControllerBase
{
    private readonly Entity _entity = new(new Id&lt;Guid&gt;(Guid.NewGuid()), "Entity");

    [HttpGet]
    public Entity Get() =&gt; _entity;

    [HttpPost]
    public Guid Post([FromBody] CreateEntity request) =&gt; request.Id.Value;
}

public class CreateEntity
{
    public Id&lt;Guid&gt; Id { get; set; }
    public string Name { get; set; }
}</pre>
<p><span style="font-weight: 400;">Let’s make a request GET /api/entities. It should return an instance of an Entity class that is part of the controller. We generate an id automatically in the application, but in a response, it should be encrypted. And here’s the response:</span></p>
<pre class="crayon-plain-tag">{
  "id": "vqvKf2FDGuZ/X7YfQd5zb2oqY6TeKggN9kGNUh2/x38mHqRSl5str25XKGX9qfTl",
  "name": "Entity"
}</pre>
<p><span style="font-weight: 400;">As you see, it’s impossible even to predict what real value is hidden beneath the cipher so we can sleep well.</span></p>
<p><span style="font-weight: 400;">Finally, let’s make a request POST /api/entities that should return an encrypted Guid value. We’ll use the response from the previous request as a body. The response of the POST endpoint:</span></p>
<pre class="crayon-plain-tag">"ca51d067-11e2-4ccc-a0d0-7ac190b994c9"</pre>
<h2><span style="font-weight: 400;">Conclusion</span></h2>
<p><span style="font-weight: 400;">Although this implementation of indirect object reference prevention implies some far-reaching features of the application, such as an obligation to use some specific class for identifiers, it still leaves a lot of stuff under the hood, so we shouldn’t deal with encryption or decryption manually.</span></p>
<p><span style="font-weight: 400;">You can extend and improve this example in multiple ways:</span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Store an encrypted version of the id inside Id&lt;T&gt; class to always know in what form it’ll be returned to the client</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Implement your encryptor to change the size of the encrypted value or the padding mode (</span><span style="font-weight: 400;">ISO10126, for example, will generate a unique ending each time on encryption)</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Create JSON converter factory sticking to best practices suggested by Microsoft</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Or maybe something else</span></li>
</ul>
<p><span style="font-weight: 400;">This foundation was meant to keep simple, but it serves one purpose: to show how to implement IDOR prevention in <span style="color: #000000;"><a style="color: #000000;" href="https://binary-studio.com/2021/08/18/hateoas-in-asp-net-core/">ASP.NET</a></span> Core application.</span></p>
<p>Source code: https://github.com/Jyuart/IDORP</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/11/01/idor-prevention-in-asp-net-core/">IDOR prevention in ASP.NET Core</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2021/11/01/idor-prevention-in-asp-net-core/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The product owner comes and says: We need to rewrite everything from Node to Deno&#8230;</title>
		<link>https://binary-studio.com/2021/10/05/deno-js-ts-runtime/</link>
					<comments>https://binary-studio.com/2021/10/05/deno-js-ts-runtime/#respond</comments>
		
		<dc:creator><![CDATA[Vladyslav Zubko]]></dc:creator>
		<pubDate>Tue, 05 Oct 2021 13:57:13 +0000</pubDate>
				<category><![CDATA[JS]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Deno]]></category>
		<category><![CDATA[node.js]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=20032</guid>

					<description><![CDATA[<p>Let's start with the riddle, who is shown in this photo? Most likely, you have worked with his product.&#160; Answer Ryan Dahl is a software engineer and the original developer of the Node.js (~2009 year). In January 2012, Dahl announced that he turned over the reins to NPM&#160;creator. In 2018 he&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/10/05/deno-js-ts-runtime/">The product owner comes and says: We need to rewrite everything from Node to Deno&#8230;</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[


<p><span style="font-weight: 400;">Let's start with the riddle, who is shown in this photo?</span></p>



<figure class="wp-block-image size-large"><img width="482" height="307" src="https://binary-studio.com/wp-content/uploads/2021/10/image2.jpg" alt="Ryan Dahl, deno, node.js" class="wp-image-20039" srcset="https://binary-studio.com/wp-content/uploads/2021/10/image2.jpg 482w, https://binary-studio.com/wp-content/uploads/2021/10/image2-300x191.jpg 300w" sizes="(max-width: 482px) 100vw, 482px" /></figure>



<p><span style="font-weight: 400;">Most likely, you have worked with his product.&nbsp;</span></p>



<blockquote>
<p><span style="font-weight: 400;">Answer</span></p>
<p><strong><a href="https://en.wikipedia.org/wiki/Ryan_Dahl">Ryan Dahl</a> </strong><span style="font-weight: 400;">is a software engineer and the original developer of the </span><em><b>Node.js</b></em><span style="font-weight: 400;"> (~2009 year). In January 2012, Dahl announced that he turned over the reins to </span><a href="https://en.wikipedia.org/wiki/Npm_(software)"><span style="font-weight: 400;">NPM</span></a><span style="font-weight: 400;">&nbsp;creator.</span></p>
<p><span style="font-weight: 400;">In 2018 he made a presentation </span><a href="https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;vl=en"><span style="font-weight: 400;">10 things I regret about Node.js</span></a><span style="font-weight: 400;">&nbsp;at the </span><a href="https://jsconf.com/"><span style="font-weight: 400;">JSConf</span></a><span style="font-weight: 400;">&nbsp;conference. Also, at this presentation, he announced </span><a href="https://deno.land/"><span style="font-weight: 400;">Deno</span></a><span style="font-weight: 400;">&nbsp;— a secure runtime for JavaScript and TypeScript.</span></p>
</blockquote>



<p><span style="font-weight: 400;">In this article, we will take a look at <em>Deno</em> and how it compares to <em>Node.js</em> to help understand what they have in common, how they differ and is it real that <em>Deno</em> will kill <em>Node.js</em>?</span></p>



<h2 class="rich-text block-editor-rich-text__editable" role="textbox" contenteditable="true" aria-multiline="true" aria-label="Write heading…">Project</h2>



<p>Let's imagine a situation: A product owner comes to us and tells us to rewrite the project from&nbsp;<a title="https://nodejs.org" href="https://nodejs.org/" data-href="https://nodejs.org">Node</a>&nbsp;to&nbsp;<a title="https://deno.land" href="https://deno.land/" data-href="https://deno.land">Deno</a>.</p>
<p>But why? Who knows, it’s just an example.&nbsp;</p>
<p class="code-line" data-line="18">For now, let's imagine that there is no other way around this decision and we need to do it. But then what? Do we really need to rewrite most of the code in the project?</p>
<p class="code-line" data-line="20">Let's check this with an example of a small project.</p>



<pre class="crayon-plain-tag">├── node_modules
├── public
├── src/
│   ├── api/
│   │   ├── /* apis */
│   │   └── api.ts
│   ├── common/
│   │   ├── enums/
│   │   │   ├── /* enums */
│   │   │   └── index.ts
│   │   ├── interfaces/
│   │   │   ├── /* interfaces */
│   │   │   └── index.ts
│   │   └── types/
│   │       ├── /* types */
│   │       └── index.ts
│   ├── helpers/
│   │   ├── /* helpers */
│   │   └── index.ts
│   ├── repositories/
│   │   ├── /* repositories */
│   │   └── repositories.ts
│   ├── services/
│   │   ├── /* services */
│   │   └── services.ts
│   └── server.ts
├── .env
├── .eslintrc.yml
├── package-lock.json
├── package-lock.json
└── tsconfig.json</pre>



<p style="text-align: center;">Project structure</p>



<pre class="crayon-plain-tag">// package.json
 
{
 &quot;private&quot;: true,
 &quot;scripts&quot;: {
   &quot;lint:js&quot;: &quot;eslint --ext .js,.ts src&quot;,
   &quot;lint&quot;: &quot;npm run lint:js&quot;,
   &quot;start&quot;: &quot;nodemon --exec ts-node --files -r dotenv/config ./src/server.ts&quot;
 },
 &quot;dependencies&quot;: {
   &quot;axios&quot;: &quot;0.21.1&quot;,
   &quot;dotenv&quot;: &quot;8.2.0&quot;,
   &quot;koa&quot;: &quot;2.13.1&quot;,
   &quot;koa-bodyparser&quot;: &quot;4.3.0&quot;,
   &quot;koa-router&quot;: &quot;10.0.0&quot;,
   &quot;koa-static&quot;: &quot;5.0.0&quot;
 },
 &quot;devDependencies&quot;: {
   &quot;@types/jest&quot;: &quot;26.0.22&quot;,
   &quot;@types/koa&quot;: &quot;2.13.1&quot;,
   &quot;@types/koa-bodyparser&quot;: &quot;4.3.0&quot;,
   &quot;@types/koa-router&quot;: &quot;7.4.2&quot;,
   &quot;@types/koa-static&quot;: &quot;4.0.1&quot;,
   &quot;@types/node&quot;: &quot;14.14.41&quot;,
   &quot;@typescript-eslint/eslint-plugin&quot;: &quot;4.22.0&quot;,
   &quot;@typescript-eslint/parser&quot;: &quot;4.22.0&quot;,
   &quot;eslint&quot;: &quot;7.24.0&quot;,
   &quot;jest&quot;: &quot;26.6.3&quot;,
   &quot;nodemon&quot;: &quot;2.0.7&quot;,
   &quot;prettier&quot;: &quot;2.2.1&quot;,
   &quot;ts-jest&quot;: &quot;26.5.5&quot;,
   &quot;ts-node&quot;: &quot;9.1.1&quot;,
   &quot;typescript&quot;: &quot;4.2.4&quot;
 }
}</pre>



<p style="text-align: center;">Dependencies</p>



<pre class="crayon-plain-tag">// src/server.ts
 
import { resolve } from 'path';
import Koa from 'koa';
import serve from 'koa-static';
import Router from 'koa-router';
import bodyParser from 'koa-bodyparser';
import { ENV } from './common/enums';
import { initRepositories } from './repositories/repositories';
import { initServices } from './services/services';
import { initApis } from './api/api';
 
const app = new Koa();
 
app.use(bodyParser());
 
const repositories = initRepositories();
 
const services = initServices({
 repositories,
});
 
const apiRouter = initApis({
 Router,
 services,
});
 
app.use(apiRouter.routes());
 
app.use(serve(resolve(__dirname, '../public')));
 
app.listen(ENV.APP.SERVER_PORT);
 
console.log(`Listening to connections on port &mdash; ${ENV.APP.SERVER_PORT}`);</pre>



<p style="text-align: center;">Root file</p>



<p>Nothing special. The project is written using a node-framework -&nbsp;<a title="https://koajs.com" href="https://koajs.com/" data-href="https://koajs.com">Koa</a>&nbsp;(next generation of the&nbsp;<a title="https://expressjs.com" href="https://expressjs.com/" data-href="https://expressjs.com">Express</a>&nbsp;node-framework).</p>



<p>What it can do:</p>



<ul>
<li class="code-line" data-line="140">Serve static content</li>
</ul>



<pre class="crayon-plain-tag">&gt; curl &quot;http://localhost:3000&quot;

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Document&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Hello world ?&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>



<ul>
<li class="code-line" data-line="159">Has a posts api (wrapper for the&nbsp;<a title="https://jsonplaceholder.typicode.com" href="https://jsonplaceholder.typicode.com/" data-href="https://jsonplaceholder.typicode.com">jsonplaceholder</a>&nbsp;service).</li>
</ul>



<pre class="crayon-plain-tag">&gt; curl &quot;http://localhost:3000/api/v1/posts/1&quot;

{&quot;userId&quot;:1,&quot;id&quot;:1,&quot;title&quot;:&quot;sunt aut facere repellat provident occaecati excepturi optio reprehenderit&quot;,&quot;body&quot;:&quot;quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto&quot;}</pre>



<ul>
<li class="code-line" data-line="167">Has a books CRUD api (all data is stored in the&nbsp;<code>json</code>&nbsp;format).</li>
</ul>



<pre class="crayon-plain-tag">&gt; curl &quot;http://localhost:3000/api/v1/books/1&quot;

{&quot;id&quot;:&quot;1&quot;,&quot;name&quot;:&quot;DDD&quot;}</pre>



<p>That's all. Perfect!</p>
<p>Let's move on to the most interesting part.</p>



<h2>From Node to Deno</h2>



<p class="code-line" data-line="182">Before we start, let's take a look at the definition of these two technologies that we can find on the technology homepage.</p>
<p class="code-line" data-line="184"><a title="https://nodejs.org/en" href="https://nodejs.org/en" data-href="https://nodejs.org/en">Node</a>&nbsp;— is a JavaScript runtime.</p>
<p class="code-line" data-line="186"><a title="https://deno.land" href="https://deno.land/" data-href="https://deno.land">Deno</a>&nbsp;— is a secure runtime for JavaScript and TypeScript.</p>
<p class="code-line" data-line="188">Both definitions contain&nbsp;<code>runtime</code>&nbsp;and&nbsp;<code>JavaScript</code>. Does it mean that we can run the same code on both platforms? Not at all.</p>
<p class="code-line" data-line="190">Let's try to run the code that we wrote on NodeJS base using Deno (if you don't have Deno installed yet, you can find how to do it&nbsp;<a title="https://deno.land/#installation" href="https://deno.land/#installation" data-href="https://deno.land/#installation">here</a>):</p>



<pre class="crayon-plain-tag">&gt; deno run src/server.ts</pre>



<p>Aaaand we get an error:</p>



<pre class="crayon-plain-tag">error: Cannot resolve module &quot;file:///src/services/services&quot; from &quot;file:///src/server.ts&quot;.
 at file:///src/server.ts:8:0</pre>



<p class="code-line" data-line="203">But interestingly, we did not receive an error saying that we use TypeScript code. This is because Deno supports TypeScript out of the box!</p>
<p class="code-line" data-line="205">If we tried to run code written with TypeScript in NodeJS without using&nbsp;<code>ts-node</code>&nbsp;(or any other&nbsp;<em>additional package</em>), we would immediately get errors about the unknown syntax.</p>
<p class="code-line" data-line="207">Okay, let's try to fix the differences between Node and Deno.</p>
<p class="code-line" data-line="209">First of all, let's install an&nbsp;<a title="https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno" href="https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno" data-href="https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno">official extension</a>&nbsp;to help us develop on Deno and add this to the editor settings:</p>



<pre class="crayon-plain-tag">// .vscode/settings.json
 
{
 &quot;deno.enable&quot;: true,
 &quot;deno.lint&quot;: true,
 &quot;deno.unstable&quot;: true
}</pre>



<p>Then, let's remove the things that are completely&nbsp;<strong>useless</strong>&nbsp;for Deno that are in NodeJS.</p>



<pre class="crayon-plain-tag">&gt; rm -rf node_modules package-lock.json package.json</pre>



<p class="code-line" data-line="227">Stop what? Where do we store our packages now?</p>
<p class="code-line" data-line="229">Do not worry, we will store the dependencies&nbsp;<em>we need</em>&nbsp;here:</p>



<pre class="crayon-plain-tag">// src/dependencies.ts
 
import 'https://deno.land/x/dotenv/load.ts';
import * as Oak from 'https://deno.land/x/oak/mod.ts';
 
export { Oak };</pre>



<p class="code-line" data-line="240">Two questions immediately arise: what is&nbsp;<code>dependencies.ts</code>&nbsp;and why do we use a link to import packages?</p>
<p class="code-line" data-line="242">Let's start from the end. Two reasons that Ryan talked about in his&nbsp;<a title="https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;t=1369s" href="https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;t=1369s" data-href="https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;t=1369s">presentation</a>&nbsp;and that he tried to fix this in Deno are&nbsp;<code>node_modules</code>&nbsp;and&nbsp;<code>package.json</code>.</p>
<p class="code-line" data-line="244">Why:</p>
<p><code>package.json</code>:</p>
<ul>
<li class="code-line" data-line="247">Allow Node's&nbsp;<code>require()</code>&nbsp;to inspect package.json files for "main";</li>
<li class="code-line" data-line="248">Included NPM in the Node distribution, which much made it the defacto standard;</li>
<li class="code-line" data-line="249">It's unfortunate that there is centralized (privately controlled even) repository for modules;</li>
<li class="code-line" data-line="250">Allowing&nbsp;<code>package.json</code>&nbsp;gave rise to the concept of a "module" as a directory of files;</li>
<li class="code-line" data-line="251">This is no a strictly necessary abstraction - and one that doesn't exist on the web;</li>
<li class="code-line" data-line="252"><code>package.json</code>&nbsp;now includes all sorts of unnecessary information. License? Repository? Description? It's boilerplate noise;</li>
<li class="code-line" data-line="253">If only relative files and URLs were used when importing, the path defines the version. There is no need to list dependencies.</li>
</ul>
<p><code>node_modules</code>:</p>
<ul>
<li class="code-line" data-line="256">It massively complicates the module resolution algorithm;</li>
<li class="code-line" data-line="257">vendored-by-default has good intentions, but in practice just using&nbsp;<code>$NODE_PATH</code>&nbsp;wouldn't have precluded that;</li>
<li class="code-line" data-line="258">Deviates greatly from browser semantics;</li>
<li class="code-line" data-line="259">It's my fault and I'm very sorry;</li>
<li class="code-line" data-line="260">Unfortunately it's impossible to undo now.</li>
</ul>
<p class="code-line" data-line="262">(The reasons are taken from Dahl's presentation). When the program is launched for the first time, modules are downloaded and cached in the system. And when reused, they will be taken from there. While reusing modules, they will be taken from the cache.</p>
<p class="code-line" data-line="264">Now about&nbsp;<code>dependencies.ts</code>. It's just a file that I created to store all third-party project's dependencies (the name can be whatever). Third-party modules can be included in any part of the program but this is not a good practice. It is better to keep all the modules in one place.</p>
<p class="code-line" data-line="266">Let's try to run the code again. We get the following error:</p>



<pre class="crayon-plain-tag">error: Is a directory (os error 21)
 at file:///src/server.ts:6:0</pre>



<p>On the sixth line we have this:</p>



<pre class="crayon-plain-tag">// src/server.ts
 
import { ENV } from './common/enums';
 
// src/common/enums/index.ts
 
export * from './api';
export * from './app';
export * from './file';
export * from './http';</pre>



<p class="code-line" data-line="288">Everything looks fine. What is the problem?</p>
<p class="code-line" data-line="290">It would seem that we can miss the file name if the file is called&nbsp;<code>index</code>.</p>
<p class="code-line" data-line="292">This is possible but only in NodeJS. In Deno we must always explicitly specify the file with its extension.</p>
<p class="code-line" data-line="294">These are two more things Dahl regrets about Node:</p>
<p><code>index.js</code>:</p>
<ul>
<li class="code-line" data-line="296">I thought it was cute because there was&nbsp;<code>index.html</code>;</li>
<li class="code-line" data-line="298">It needlessly complicated the module loading system;</li>
<li class="code-line" data-line="299">It became especially unnecessary after&nbsp;<code>require</code>&nbsp;supported&nbsp;<code>package.json</code>.</li>
</ul>
<p>modules without the extension:</p>
<ul>
<li class="code-line" data-line="302">Needlessly less explicit;</li>
<li class="code-line" data-line="303">Not how browser JavaScript works. You cannot omit the&nbsp;<code>.js</code>&nbsp;in a script tag src attribute;</li>
<li class="code-line" data-line="304">The module loader has to query the file system at multiple locations trying to guess what the user intended.</li>
</ul>
<p class="code-line" data-line="307">Let's fix this and a few other errors that we will run into.</p>



<ol>
<li>Resole magic names</li>
</ol>



<pre class="crayon-plain-tag">// src/common/enums/index.ts

export * from './api/index.ts';
export * from './app/index.ts';
export * from './file/index.js';
export * from './http/index.ts';</pre>



<p>2. Resolve magic variables/functions/modules that are only available in Node</p>



<pre class="crayon-plain-tag">error: Uncaught ReferenceError: __dirname is not defined

- app.use(serve(resolve(__dirname, '../public')));
+ await Oak.send(ctx, ctx.request.url.pathname, {
+   root: 'public',
+   index: 'index.html',
+ });</pre>





<pre class="crayon-plain-tag">error: Uncaught ReferenceError: require is not defined

- const contentType = require('./content-type.enum');
+ import contentType from './content-type.enum.ts';</pre>



<pre class="crayon-plain-tag">error: Uncaught ReferenceError: module is not defined

- module.exports = {
+ export {</pre>



<p>3. Resolve take variables from env</p>



<pre class="crayon-plain-tag">// src/common/enums/app/env.enum.ts

- const { PORT, PLACEHOLDER_API_URL } = process.env;

const ENV = {
  APP: {
-    SERVER_PORT: &amp;lt;string&gt;PORT,
+    SERVER_PORT: Number(Deno.env.get('PORT')),
  },
  API: {
    V1_PATH: '/api/v1',
  },
  API_URL: {
-    PLACEHOLDER_API: &amp;lt;string&gt;PLACEHOLDER_API_URL,
+    PLACEHOLDER_API: &amp;lt;string&gt;Deno.env.get('PLACEHOLDER_API_URL'),
  },
} as const;</pre>



<p>4. Resolve writeFile/readFile helpers</p>



<pre class="crayon-plain-tag">// src/helpers/fs/read-file/read-file.helper.helper.ts

- import fs from 'fs/promises';

- const readFile = (path: string): Promise&amp;lt;Buffer&gt; =&gt; {
-   return fs.readFile(path);
+ const readFile = (path: string): Promise&amp;lt;string&gt; =&gt; {
+   return Deno.readTextFile(path);
};

export { readFile };

// src/helpers/fs/write-file/write-file.helper.helper.ts
- import fs from 'fs/promises';

- const writeFile = (path: string, data: string | Uint8Array): Promise&amp;lt;void&gt; =&gt; {
-   return fs.writeFile(path, data);
+ const writeFile = (path: string, data: Uint8Array): Promise&amp;lt;void&gt; =&gt; {
+   return Deno.writeFile(path, data);
};

export { writeFile };</pre>



<p>5. Resolve Paths</p>



<pre class="crayon-plain-tag">src/repositories/book/books.repository.ts

...

- const booksDataPath = path.resolve(__dirname, './books.json');
+ const booksDataPath = new URL('./books.json', import.meta.url).pathname;

class Books implements IRepository&amp;lt;Book&gt; {

  ...

  private _saveBooks(books: Book&amp;#91;]): Promise&amp;lt;void&gt; {
-    return writeFile(booksDataPath, JSON.stringify(books));
+    return writeFile(
+      booksDataPath,
+      new TextEncoder().encode(JSON.stringify(books)),
+    );
  }
}</pre>



<p>6. Fetch out of the box</p>



<pre class="crayon-plain-tag">// src/services/http/http.service.ts

class Http {
-  #http: AxiosInstance;
-
-  constructor() {
-    this.#http = axios.create({});
-  }

  public load&amp;lt;T = unknown&gt;(
    url: string,
-    options: AxiosRequestConfig = {
+    options: RequestInit = {
      method: HttpMethod.GET,
    },
  ): Promise&amp;lt;T&gt; {
-    return this.#http
-      .request&amp;lt;T&gt;({ url, ...options })
-      .then(Http.getData)
-      .catch(Http.catchError);
+    return fetch(url, options)
+      .then(this._checkStatus)
+      .then((res) =&gt; this._parseJSON&amp;lt;T&gt;(res))
+      .catch(this._throwError);
  }

-  static getData&amp;lt;T&gt;(response: AxiosResponse&amp;lt;T&gt;): T {
-    return response.data;
+  private _checkStatus(response: Response): Response | never {
+    if (!response.ok) {
+      throw new Error(response.statusText);
+    }
+
+    return response;
  }

-  static catchError(err: AxiosError&amp;lt;unknown&gt;): never {
-    const { response } = err;
+  private _parseJSON&amp;lt;T&gt;(response: Response): Promise&amp;lt;T&gt; {
+    return response.json();
  }

-    throw new Error(response?.statusText);
+  private _throwError(err: Error): never {
+    throw err;
  }
}</pre>



<p>Of course there were more changes, but these are the most interesting things that deserve attention.</p>



<pre class="crayon-plain-tag">// src/server.ts
 
import { Oak } from './dependencies.ts';
import { ENV } from './common/enums/index.ts';
import { initRepositories } from './repositories/repositories.ts';
import { initServices } from './services/services.ts';
import { initApis } from './api/api.ts';
 
const app = new Oak.Application();
 
const repositories = initRepositories();
 
const services = initServices({
 repositories,
});
 
initApis({
 Router: Oak.Router,
 services,
 app,
});
 
app.use(async (ctx) =&gt; {
 await Oak.send(ctx, ctx.request.url.pathname, {
   root: 'public',
   index: 'index.html',
 });
});
 
app.listen({
 port: ENV.APP.SERVER_PORT,
});
 
console.log(`Listening to connections on port &mdash; ${ENV.APP.SERVER_PORT}`);</pre>



<p class="code-line" data-line="505">Root file using Deno</p>
<p class="code-line" data-line="507">Almost the same, isn't it?&nbsp;</p>



<h2 class="rich-text block-editor-rich-text__editable" role="textbox" contenteditable="true" aria-multiline="true" aria-label="Write heading…">Permissions</h2>



<p>Finally, let's run our refactored app!</p>



<p>We are still getting the error:</p>



<pre class="crayon-plain-tag">error: Uncaught PermissionDenied: Requires env access to &quot;PORT&quot;, run again with the --allow-env flag
   SERVER_PORT: Deno.env.get('PORT'),</pre>



<p class="code-line" data-line="520">But this time it is an error that was not received before.</p>
<p class="code-line" data-line="522">Another issue which Ryan regrets is security in NodeJS:</p>
<ul>
<li class="code-line" data-line="524">V8 by itself is a very good security sandbox;</li>
<li class="code-line" data-line="525">Had I put more thought into how that could be maintained for certain applications, Node could have had some nice security guarantees not available in any other language;</li>
<li class="code-line" data-line="526">Example: Your linter shouldn't get complete access to your computer and network.</li>
</ul>
<p class="code-line" data-line="528">Every time we run a program on Deno, we need to specify the appropriate permissions that it will possess.</p>
<p class="code-line" data-line="530">To run our app we need to use these permissions:</p>



<pre class="crayon-plain-tag">&gt; deno run --allow-env --allow-read --allow-write --allow-net src/server.ts</pre>



<p><em>By this&nbsp;<a title="https://deno.land/manual/getting_started/permissions#permissions-list" href="https://deno.land/manual/getting_started/permissions#permissions-list" data-href="https://deno.land/manual/getting_started/permissions#permissions-list">link</a>&nbsp;you can find a list of all permissions.</em></p>
<p>Let's try to run it again:</p>



<pre class="crayon-plain-tag">&gt; deno run --allow-env --allow-read --allow-write --allow-net src/server.ts
 
Listening to connections on port &mdash; 3000</pre>



<p>Let's try to call the APIs:</p>



<pre class="crayon-plain-tag">&gt; curl &quot;http://localhost:3000/api/v1/posts/1&quot;
 
{&quot;userId&quot;:1,&quot;id&quot;:1,&quot;title&quot;:&quot;sunt aut facere repellat provident occaecati excepturi optio reprehenderit&quot;,&quot;body&quot;:&quot;quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto&quot;}</pre>



<pre class="crayon-plain-tag">&gt; curl &quot;http://localhost:3000/api/v1/books/1&quot;
 
{&quot;id&quot;:&quot;1&quot;,&quot;name&quot;:&quot;DDD&quot;}</pre>



<p class="code-line" data-line="559">Everything works!&nbsp;</p>
<p class="code-line" data-line="561">But look at the code differences:</p>



<figure class="wp-block-image size-large"><img width="1024" height="128" src="https://binary-studio.com/wp-content/uploads/2021/10/image1-1024x128.jpg" alt="development to staging, deno" class="wp-image-20074" srcset="https://binary-studio.com/wp-content/uploads/2021/10/image1-1024x128.jpg 1024w, https://binary-studio.com/wp-content/uploads/2021/10/image1-300x38.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/10/image1-768x96.jpg 768w, https://binary-studio.com/wp-content/uploads/2021/10/image1-1536x192.jpg 1536w, https://binary-studio.com/wp-content/uploads/2021/10/image1-624x78.jpg 624w, https://binary-studio.com/wp-content/uploads/2021/10/image1.jpg 1999w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="code-line" data-line="559">Amazing, isn't it?</p>
<p class="code-line" data-line="566"><em>Okay-okay, most of the changes (almost all) are due to dependencies, since now we only have&nbsp;<strong>2</strong>&nbsp;dependencies.</em></p>
<h2 id="easter-eggs" class="code-line" data-line="568">Easter eggs</h2>
<p class="code-line" data-line="570">Do you like easter eggs? Hope so ?</p>
<p class="code-line" data-line="572">Let's see something:</p>



<pre class="crayon-plain-tag">const checkIsSameStr = (stringA: string, stringB: string): boolean =&gt; {
 return Array.from(stringA.toLowerCase()).every((it) =&gt; {
   return stringB.toLowerCase().includes(it)
 })
}
 
const isEasterEgg = checkIsSameStr('Node', 'Deno'); // true
 
// Koa - the middleware framework for Node
// Oak - the middleware framework for Deno
const isEasterEgg = checkIsSameStr('Koa', 'Oak'); // true</pre>



<p class="code-line" data-line="588">Not sure if this was done on purpose (I hope so), but there is something similar here, isn't there?&nbsp;</p>
<p class="code-line" data-line="590"><em>(There are a number of other packages that are named similarly.)</em></p>



<h2 id="conclusions" class="code-line" data-line="592">Conclusions</h2>
<p class="code-line" data-line="594">Until recently Node had almost no competitors (<a title="https://en.wikipedia.org/wiki/Node.js#History" href="https://en.wikipedia.org/wiki/Node.js#History" data-href="https://en.wikipedia.org/wiki/Node.js#History">io.js</a> ?) and was almost the only platform where we could run JavaScript on the server.</p>
<p class="code-line" data-line="596"><span style="color: #000000;">But now, Node has a worthy competitor, Deno — a <strong>secure</strong> runtime for <a style="color: #000000;" href="https://binary-studio.com/2021/08/04/js-and-everyday-data-structures/"><strong>JavaScript</strong></a> and <strong>TypeScript</strong>, who will step on its heels every day.</span></p>
<p class="code-line" data-line="598">Competition is usually always good!</p>
<p class="code-line" data-line="600">This article does not cover all topics such as <a title="https://deno.land/manual@v1.9.0/tools/linter" href="https://deno.land/manual@v1.9.0/tools/linter" data-href="https://deno.land/manual@v1.9.0/tools/linter">code linting</a>, <a title="https://deno.land/manual/tools/formatter" href="https://deno.land/manual/tools/formatter" data-href="https://deno.land/manual/tools/formatter">code formatting</a>, <a title="https://deno.land/manual@v1.9.0/testing" href="https://deno.land/manual@v1.9.0/testing" data-href="https://deno.land/manual@v1.9.0/testing">code testing</a>, etc. By the way, <em>most of these things Deno has out of the box</em> ?</p>
<p class="code-line" data-line="602">There is no need to run and rewrite everything but at least everyone should take a look and try Deno. People who have already worked with Node shouldn't take a lot of effort to make friends with this beautiful technology.</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/10/05/deno-js-ts-runtime/">The product owner comes and says: We need to rewrite everything from Node to Deno&#8230;</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2021/10/05/deno-js-ts-runtime/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>What is an onsite and offshore model?</title>
		<link>https://binary-studio.com/2021/09/08/what-is-an-onsite-and-offshore-model/</link>
					<comments>https://binary-studio.com/2021/09/08/what-is-an-onsite-and-offshore-model/#respond</comments>
		
		<dc:creator><![CDATA[Edward Robe]]></dc:creator>
		<pubDate>Wed, 08 Sep 2021 14:28:09 +0000</pubDate>
				<category><![CDATA[Process]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[offshore]]></category>
		<category><![CDATA[onsite]]></category>
		<category><![CDATA[outsourcing]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=19937</guid>

					<description><![CDATA[<p>It is quite obvious that the modern world is a constantly changing and global organism. Keeping pace with the crazy rhythm is a task that only the most motivated and intelligent people can accomplish. The streams of information generated every day, hour, minute, without any exaggeration, are capable of striking the&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/09/08/what-is-an-onsite-and-offshore-model/">What is an onsite and offshore model?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><span style="font-weight: 400;">It is quite obvious that the modern world is a constantly changing and global organism. Keeping pace with the crazy rhythm is a task that only the most motivated and intelligent people can accomplish. The streams of information generated every day, hour, minute, without any exaggeration, are capable of striking the imagination. If we try to analyze this value, the results will be even more impressive. Just imagine: over the past two years, humanity has generated more data than over the entire previous period of its existence. And this fact is quite capable of illustrating how colossal arrays of information we must process today.</span></p>
<p><span style="font-weight: 400;">As you can imagine, the IT industry is at the forefront of this activity. It is this industry that not only processes all quintillion of data. Systematization, analytics, and, of course, generation. These are the tasks that modern companies perform. The results of their activities, at the same time, make our life richer and better, opening up new, unimaginable horizons of modern technologies and the future, descended from the screens of fantastic films and the pages of novels. This work is more like art and, with its creativity, forms an absolutely new reality. And without a doubt, this is a resource-intensive and difficult job. It is vital to avoid burnout and not turn your favorite activity into an excruciating routine, where the result changes over time.</span></p>
<p><span style="font-weight: 400;">This is why thousands of programs and strategies are developed that minimize costs and optimize resources. The correct and balanced use of such tools will allow not only to diversify efforts, costs, and human potential. But it will also save time for the production of additional projects and the implementation of new ideas and dreams.</span></p>
<p><span style="font-weight: 400;">A project delivery model - is one of the cornerstones of the modern developing IT industry. It is unlikely that you have not heard about it, and if you have not, you have to get acquainted with this concept. This term is being used more and more in the industry. And its relevance is becoming more evident. Especially in the context of the Covid-19 pandemic, which completely changed the rules of the game. Especially when it comes to workforce management, consolidation, and segregation of intellectual assets for optimal results in software development.</span></p>
<h2><span style="font-weight: 400;">What is an onsite model?</span></h2>
<p><span style="font-weight: 400;">Onsite or the so-called onshore delivery model is a prevalent concept today, a topic of discussion and controversy regarding its application. As you study this model, don't be fooled, because the onsite and onshore term is used in many areas of software development. Moreover, these concepts have their own meanings in other areas of our life: geography and economics. But, in the context in which we discuss this concept today, onsite means a method of software development and delivery in which qualified developer specialists carry out activities at the client's site.</span></p>
<p><span style="font-weight: 400;">The result of this symbiosis is the collaboration of the contractor's specialists and the customer's employees. Accumulation of information, development, project support, and implementation of best practices - all these tasks must be solved by a temporary team staffed by the customer and the contractor.</span></p>
<p><span style="font-weight: 400;">This model has obvious advantages, but at the same time, a sufficient number of negative aspects. The lack of clear management vertical because the tasks are set by the customer, implemented by the performer, and performed by joint efforts, can create chaos. Ah, chaos is not the best ally when trying to create something new and innovative.</span></p>
<h2><span style="font-weight: 400;">The key benefits of the onsite model.</span></h2>
<p><span style="font-weight: 400;">But, on the other hand, if you are creating a reengineering project or another project based on a repetitive cycle of tasks, this approach to development can work and be much more effective. The same statement is true if, at the initial stage, the customer does not have a clear understanding of the project and the requirements for it.</span></p>
<p><span style="font-weight: 400;">The constant interaction of the customer's specialists and the development team, with the right planning and understanding of the risks, can bring amazing results with less effort.</span></p>
<p><span style="font-weight: 400;">The onshore model is usually ideal when the end-user needs a quick and high-quality improvement to existing systems. Or when you need an organic and rapid introduction of new technologies. In such cases, the advantage of this algorithm will be your trump card.</span></p>
<p><span style="font-weight: 400;">A simple and fast exchange of information is almost the main factor that the onshore type will offer. Starting with global information clusters, which will form the basis of the product, and ending with small messages on current affairs. Information flows move faster, making it possible to operate on up-to-date data. All parties involved in the process have the opportunity to keep their finger on the pulse of the project.</span></p>
<p><span style="font-weight: 400;">In addition, face-to-face communication, which has been greatly underestimated lately, can be just that boost, which will make the difference. Indeed, sometimes a short personal conversation helps to avoid any future problems.</span></p>
<p><span style="font-weight: 400;">Last-day crunch will not be your issue either. Indeed, the very plot of this type of work leaves no chances to miss something important in the development process.</span></p>
<h2><span style="font-weight: 400;">What is the offshore model?</span></h2>
<p><span style="font-weight: 400;">The offshore model is a true child of our time. Our today's technologies have not only opened up new prospects for information processing and the creation of unique products. As it turned out, they became salvation in the face of the alarming threat of the COVID-19 pandemic. Remote work managed to keep us on the edge of the abyss until scientists invented a vaccine.</span></p>
<p><span style="font-weight: 400;">The off-shore algorithm is all about it. Outsourcing has a single point of concentration. Usually, this point is the developer's site. The best part of this system is the lack of reference to the customer, executor, employees, and other persons involved in the development. Today, products are made by people who may never see each other.</span></p>
<p><span style="font-weight: 400;">Of course, permanent communication between all team members goes through instant messengers, video calls and conferences, and other communication programs. This approach will definitely work for you. Especially if the initial data for the project have clear data and structure, and you have a plan or better - clear SRS documentation.</span></p>
<h2><span style="font-weight: 400;">The key benefits of outsourcing.</span></h2>
<p><span style="font-weight: 400;">The benefits of <a href="https://binary-studio.com/2021/07/20/successfully-managing-outsourced-projects/">outsourcing</a> may only be unknown to you if you haven't followed the news for the past ten years. This type of work organization has erased the boundaries in the world. And, the best area of ​​application of this approach is long-term, large projects.</span></p>
<p><span style="font-weight: 400;">If you follow this path, you will receive an unlimited choice of specialists. You will be able to hire people based on your priorities. Either hire the best and most expensive specialists from all over the world or hire literate people from countries with low costs for the sake of the economy. The pandemic has shown that the result does not depend on where the specialist works, and he does it in the office or at home.</span></p>
<p><span style="font-weight: 400;">Predictable and understandable prices and guarantees of partner companies and exchanges make this model efficient, financially secure, and controllable. The offshore model requires specific skills in control and organization of the workflow, but it can bring excellent results.</span></p>
<h2><span style="font-weight: 400;">What is the difference between onsite and offshore?</span></h2>
<p><span style="font-weight: 400;">The difference between onsite and offshore is obvious if you carefully read the previous sections of our article. You have two equivalent tools for building a productive and high-quality vertical of the work process in your hands.</span></p>
<p><span style="font-weight: 400;">Relatively speaking, the difference lies in the density of the working atmosphere and the length of communication steps. By scaling the step plan and algorithms and taking into account the final task, you can choose the type of model optimal for your project.</span></p>
<p><span style="font-weight: 400;">In a simplified version, everything can be explained. With an onshore model, you have a simple view of yourself and the client. There is a mixed team of employees from both sides between you. This creates a very dense and cozy atmosphere that has a high response rate.</span></p>
<p><span style="font-weight: 400;">The offshore model consists of two managers - your project manager and the client`s manager. These employees provide interaction between your disparate remote team and the customer's team, which implements your best practices.</span></p>
<h2><span style="font-weight: 400;">What is the onsite and offshore model? Hybrid model.</span></h2>
<p><span style="font-weight: 400;">As you can imagine, no one has the right to limit your choice. Moreover, the cornerstone of the IT industry is wide diversity and unknown paths. Having new ideas - do not hesitate to implement them because they can lead to unexpected success and amazing results. This is how the hybrid model appeared.</span></p>
<p><span style="font-weight: 400;">Already from the name, it becomes clear that its essence lies in crossing all the best aspects from both models. The mixing of working algorithms makes it possible to pose the most complex problems with variable variants of achievement. A localized team and outsourced specialists combined in the right proportion are the ultimate solutions for your project.</span></p>
<p><span style="font-weight: 400;">This model often employs 30 percent of the local staff and 70 percent of the hired people in the remote mode of operation. People in a stationary team are often engaged in the accumulation of primary information and requests, planning, and building communication with the client. At the same time, the offshore team is engaged in monitoring and step-by-step analysis of the product, its support, and solving local problems according to requirements.</span></p>
<p><span style="font-weight: 400;">But, do not forget that the given structure is just an example. And, if you wish, you can calculate your own version for successful work or use one of the many patterns.</span></p>
<h2><span style="font-weight: 400;">The key benefits of hybrid model teams.</span></h2>
<p><span style="font-weight: 400;">It is quite logical that the benefits of the hybrid model combine all the benefits of the two primary models. What does it mean? Even more possibilities of soft regulation and mechanisms of control and management of processes. And, of course, opportunities to diversify cash costs and quickly regulate cash flows, quickly and painlessly redirecting funding in the right directions. You can reduce the cost of infrastructure and local team maintenance costs by hiring telecommuters. Or, if necessary, it will be quickly rebuilt for the development of infrastructure. Variety and flexibility will be your main weapons when using hybrid model teams.</span></p>
<p><strong>How to communicate with offshore teams.</strong></p>
<p><span style="font-weight: 400;">Communication is your key to being productive. Therefore, it will be useful to develop a strategy or entrust this step to specialists. From how the project coordinator will hear and how correctly the priorities and motion vectors will be determined. Moreover, according to the opinions of researchers, the lack of communication leads to a decrease in the exchange of information. And, reduced communication leads to a lower likelihood of success. And, at the same time, a reduced sense of success negatively affects the atmosphere in the team.</span></p>
<p><span style="font-weight: 400;">Therefore, remember that thoughtful communication will help reduce the distance between employees in different parts of the world and between management and the client.</span></p>
<p><span style="font-weight: 400;">The key to this is coordination, without which project management cannot adapt to such a work model. To do this, management must control everything: structure, infrastructure, risk management, conflict management, the team, and its organization.</span></p>
<p><strong>How to get maximum productivity from the offshore team.</strong></p>
<p><span style="font-weight: 400;">Today's reality is that sooner or later, you will have to turn to an offshore team model. How deeply this model is integrated into the structure of your company is an open question and depends only on you and your needs. This is the objective reality of the modern world. Moreover, the pandemic has shown that to achieve good results and create truly innovative projects. It is unnecessary to follow the classic paradigms and create a huge office with a schedule and many administrators.</span></p>
<p><span style="font-weight: 400;">The offshore team and its implementation will definitely become a new horizon for your aspirations. But, let's be honest, the threshold for entering the integration of new solutions is very high. And, you will probably need specialists who can ensure a quick restructuring of the business and introduce a different approach to work.</span></p>
<p><span style="font-weight: 400;">In this article, we have touched on only the most obvious offshore team model functioning issues. But, there are a great many vital little things that can ruin your life. Differences in time zones, cultural differences, even different understandings of terms - all this must be taken into account when starting a new project. And for these purposes, at least at the initial stage, it is better to attract professionals. This way, you can get the most out of your offshore team.</span></p>
<p><span style="font-weight: 400;">Modern market and information technology opportunities provide us with incredible opportunities. Our goal is simple - to be flexible and open to new ideas. Indeed, the absence of limits in our management toolkit levels out all the limits in achieving success.</span></p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/09/08/what-is-an-onsite-and-offshore-model/">What is an onsite and offshore model?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2021/09/08/what-is-an-onsite-and-offshore-model/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to secure your REST API service?</title>
		<link>https://binary-studio.com/2021/08/28/how-to-secure-your-rest-api-service/</link>
					<comments>https://binary-studio.com/2021/08/28/how-to-secure-your-rest-api-service/#respond</comments>
		
		<dc:creator><![CDATA[Vitalii Yarmus]]></dc:creator>
		<pubDate>Sat, 28 Aug 2021 08:11:01 +0000</pubDate>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">https://binary-studio.com/?p=19863</guid>

					<description><![CDATA[<p>REST API is commonly used for the communication of microservices and front-end and back-end parts of WEB and Mobile applications. It has become popular because it is intuitive, highly scalable, and easy to modify and extend. This layer hides the info from the user that he shouldn't see. So this layer&#8230;</p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/08/28/how-to-secure-your-rest-api-service/">How to secure your REST API service?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><span style="font-weight: 400;">REST API is commonly used for the communication of microservices and front-end and back-end parts of WEB and Mobile applications. It has become popular because it is intuitive, highly scalable, and easy to modify and extend. This layer hides the info from the user that he shouldn't see. So this layer can be used as the target for cyber-attack. According to </span><a href="https://salt.security/api-security-trends"><span style="font-weight: 400;">Salt Security, 91% faced security incidents in production last yea</span></a><span style="font-weight: 400;">r. </span><span style="font-weight: 400;">In this article, I would give you some pieces of advice to help you build a secure API service.</span></p>
<h2><span style="font-weight: 400;">HTTPS</span></h2>
<p><span style="font-weight: 400;">HTTP is an awesome</span><span style="font-weight: 400;"> application layer protocol, but it is not secure for login data or credit card information because it doesn’t have encryption. Cybercriminals can intercept requests with users’ sensitive data by breaking into the Wi-Fi connection or the internet provider’s network. This type of attack is called </span><a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack"><span style="font-weight: 400;">Man-in-the-middle(MitM) attack</span></a><span style="font-weight: 400;"> and it cannot be carried out if the site uses HTTPS.</span></p>
<p><span style="font-weight: 400;">The main idea behind HTTPS is the generation of a short-term key for a single session and verifying it with a long-term client-side public key and server-side private key. A session key is generated by the owner of the public key and is encrypted by it. This encrypted key is sent to the server and only the server can decrypt it. Now only the client and server know the session key with which all requests and responses are encrypted. Such type of encryption is called </span><a href="https://en.wikipedia.org/wiki/Hybrid_cryptosystem"><span style="font-weight: 400;">Hybrid cryptosystem</span></a><span style="font-weight: 400;"> and SSL/TLS are good examples of such layers.</span></p>
<p><span style="font-weight: 400;">WebSockets can also work over SSL/TLS encryption which also perfectly protects against the MitM attack.</span></p>
<p><span style="font-weight: 400;">To implement an encryption layer over your HTTP you need to gain an SSL certificate from a certificate authority. You can get it even for free with services like Let’s Encrypt. Let’s add an SSL certificate to a sample page running in Nginx.</span></p>
<p><img class="wp-image-19879 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/1-300x230.jpg" alt="" width="563" height="432" srcset="https://binary-studio.com/wp-content/uploads/2021/08/1-300x230.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/1.jpg 419w" sizes="(max-width: 563px) 100vw, 563px" /></p>
<p><span style="font-weight: 400;">As you can see Google Chrome shows that my site is not secure. To add an SSL certificate you need to enter your system info on the </span><a href="https://certbot.eff.org/"><span style="font-weight: 400;">Certbot website</span></a><span style="font-weight: 400;">.</span></p>
<p><img class="wp-image-19886 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/2-300x32.jpg" alt="" width="591" height="63" srcset="https://binary-studio.com/wp-content/uploads/2021/08/2-300x32.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/2.jpg 512w" sizes="(max-width: 591px) 100vw, 591px" /></p>
<p><span style="font-weight: 400;">And it redirects to the </span><a href="https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx"><span style="font-weight: 400;">page with instructions.</span></a><span style="font-weight: 400;"> You need to follow it and just enter your domain.</span></p>
<p><img class="wp-image-19885 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/3-300x277.jpg" alt="" width="678" height="626" srcset="https://binary-studio.com/wp-content/uploads/2021/08/3-300x277.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/3.jpg 512w" sizes="(max-width: 678px) 100vw, 678px" /></p>
<p><span style="font-weight: 400;">Now let’s check our web-site</span></p>
<p><img class="wp-image-19884 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/4-300x283.jpg" alt="" width="573" height="541" srcset="https://binary-studio.com/wp-content/uploads/2021/08/4-300x283.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/4.jpg 397w" sizes="(max-width: 573px) 100vw, 573px" /></p>
<p><span style="font-weight: 400;">It is secure ?</span></p>
<p><span style="font-weight: 400;">Now, even when cybercriminals intercept your request, it will be impossible for them to retrieve any information. It is the first and the easiest step in the way of creating a secure API.</span></p>
<p><span style="font-weight: 400;">But it also has a few disadvantages. Encrypted connection involves more computations to encrypt and decrypt data. As a result, it affects the performance of both the server and the client and introduces larger latencies. Another issue that can force you to not implement SSL/TLS encryption is the impossibility to use caching in proxy server between server and client.</span></p>
<h2><span style="font-weight: 400;">CORS</span></h2>
<p><span style="font-weight: 400;">Cross-origin resource sharing is a browser mechanism that controls access to resources. This extends the Same-origin policy which restricts scripts on one origin from accessing the data in another and is used by default in all browsers. This prevents requests from third-party sites to your server.</span></p>
<p><span style="font-weight: 400;">On the server side, you can restrict domains of sites that are allowed to send requests. Browsers will block requests from other domains. Also, it is possible to restrict the methods and headers of specific requests. For example, if I want to accept only GET requests from </span><a href="https://foo.bar"><span style="font-weight: 400;">https://foo.bar</span></a><span style="font-weight: 400;"> I can add such headers to the response</span></p>
<p><i><span style="font-weight: 400;">      Access-Control-Allow-Origin: </span></i><a href="https://foo.example"><i><span style="font-weight: 400;">https://foo.example</span></i></a></p>
<p><i><span style="font-weight: 400;">      Access-Control-Allow-Methods: GET</span></i></p>
<p><span style="font-weight: 400;">You can also specify the list of headers that can be transmitted with the request </span></p>
<p><i><span style="font-weight: 400;">      Access-Control-Allow-Headers: Content-Type, Authorization</span></i></p>
<p><span style="font-weight: 400;">There are a few more headers that </span><a href="https://fetch.spec.whatwg.org/#http-cors-protocol"><span style="font-weight: 400;">you can find here.</span></a></p>
<p><span style="font-weight: 400;">For applications that don't use cross-domain requests, CORS should be disabled so the browser will restrict any requests. But if we are setting these headers in the response, how does the browser know about them before sending a request? It sends an extra handshake using the HTTP OPTIONS method to determine if the actual request is cross-origin compatible.</span></p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"><span style="font-weight: 400;">See more on MDN</span></a></p>
<p><span style="font-weight: 400;">But you don’t need to do it manually, nowadays, all frameworks have built-in systems to implement CORS.</span></p>
<h2><span style="font-weight: 400;">Object Level Authorization</span></h2>
<p><span style="font-weight: 400;">This is the mechanism that checks if a user is allowed to do any manipulations against the data(create/read/update/delete). According to OWASP, it is the most common pitfall of modern APIs.</span></p>
<p><span style="font-weight: 400;">Here is an example of the problem:</span></p>
<p><span style="font-weight: 400;">We have authentication and it feels secure. For updating some product information manager uses such a request.</span></p>
<p><strong>      PUT /product/1</strong></p>
<p><span style="font-weight: 400;">The customer registered on the website somehow found this request and tried it to make a joke (or not). He has just authenticated and sent the same request. The product was updated. He tried other ids 2,3,4 etc. and the request worked as well. He updated the product, moreover, he can update any product. But he is not the manager and not allowed to do it</span></p>
<p><span style="font-weight: 400;">Of course, you don't want to allow someone to be able to change some data. For this purpose, you need to implement access control security. For example Role-Based Access Control. It allows restricting control based on user roles and </span><span style="font-weight: 400;">privileges.</span></p>
<p><span style="font-weight: 400;">In our server-side application we can define two roles: <code>manager</code> and <code>customer</code> with permission to read for both, and to update/add/delete only for a manager. We can assign these roles to users and save them in a database with user information and insert them in the JWT token. </span><span style="font-weight: 400;">During the authorization process, we determine the user's role and allows to make changes in the product only if the user has permission to do it.</span></p>
<p><span style="font-weight: 400;">Also, it is possible to build a hierarchy with roles, so users with higher-level roles have all permissions of their sub-roles. This makes the process of maintenance user permissions easier.</span> <a href="https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html"><span style="font-weight: 400;">There are more other access mechanisms </span><span style="font-weight: 400;">here</span></a><span style="font-weight: 400;"> </span></p>
<h2><span style="font-weight: 400;">Data filtration</span></h2>
<p><span style="font-weight: 400;">The issue with excessive data exposure is very common. Some developers rely on the front-end part to show not full data, and they throw all info from the database in response. It is the wrong approach. In the database, much private information can be saved like address, credit card numbers, etc. The backend part of the application should not rely on the front-end, it should work independently and return only that information that the user needs. </span></p>
<p><span style="font-weight: 400;">Let's imagine some social network, with a search system of users where they can find each other by name. The record with such structure is saved in the database:<br /></span></p>
<pre class="crayon-plain-tag">{
  “name”: “Matt Tress”,
  “phone”: “229-563-0840”, 
  “email”: “matt.tress@test.com”,
  “address”: “Random street, 24”
}</pre>
<p><span style="font-weight: 400;">The search system returns the list of users, and only the name is shown for the end-user. But here is the problem, even in dev-tools in browser users can see the FULL response with phone number and email.</span></p>
<p><span style="font-weight: 400;">Such problems even have big companies with a lot of resources, like Google. </span><a href="https://en.wikipedia.org/wiki/2018_Google_data_breach"><span style="font-weight: 400;">In 2018 Google got into a scandal with a data breach</span></a><span style="font-weight: 400;">. After software update Google+ API. Large number of apps that used it got access to data that users marked as private. User data from over 52 million users were exposed.</span></p>
<p><span style="font-weight: 400;">Also, it is not only a security problem, when you transmit full data, it is always bigger than the user really needs so it causes additional network load.</span></p>
<p><span style="font-weight: 400;">The other great solution to fix this problem is to use GraphQL. It is a query language for your API that provides the possibility for a client to ask only for data that is needed. But don’t forget to check user permissions in your resolvers or middleware to block access to not allowed data.</span></p>
<h2><span style="font-weight: 400;">Web Application Firewall</span></h2>
<p><span style="font-weight: 400;">Web application firewall(WAF) is a network security system for applications that use HTTP/HTTPS protocols that filter and block network traffic based on some security rules. This system helps prevent large amounts of attacks like DOS/DDOS, SQL injections, Cross-site request forgery, etc. Also, it provides functionality for blocking and tracking IP addresses, adding HTTP security headers, and others depending on specific realization. This tool also can analyze normal user behavior, which helps to detect attacks using automation tools like brute force and DDOS. There are a lot of free and paid systems on the market.</span></p>
<p><span style="font-weight: 400;">Here is how the Azure WAF is working. After creating you can attach it to the Application Gateway and it will restrict all attacks that it knows. Azure WAF has a lot of predefined rules to secure you from the most popular attacks. </span></p>
<p><span style="font-weight: 400;">To show the work of WAF I’ve created a Virtual machine with the sample apache default page and Application Gateway for it.</span></p>
<p><span style="font-weight: 400;">A simple XSS attack through the public IP of a VM is successfully (for the attacker) executed.</span></p>
<p><img class="wp-image-19883 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/5-300x98.jpg" alt="" width="737" height="240" srcset="https://binary-studio.com/wp-content/uploads/2021/08/5-300x98.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/5.jpg 512w" sizes="(max-width: 737px) 100vw, 737px" /></p>
<p><span style="font-weight: 400;">But the same attack through our Application Gateway with WAF is blocked with status 403.</span></p>
<p><img class="wp-image-19882 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/6-300x40.jpg" alt="" width="608" height="81" srcset="https://binary-studio.com/wp-content/uploads/2021/08/6-300x40.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/6.jpg 512w" sizes="(max-width: 608px) 100vw, 608px" /></p>
<p><span style="font-weight: 400;">It blocks in the same way a lot of others, more destructible attacks. It is also possible to define your own rules to restrict attacks you are experiencing with your application.</span></p>
<h2><span style="font-weight: 400;">DOS and DDOS protection</span></h2>
<p><span style="font-weight: 400;">Denial of service attack called up to overload the system making a bunch of slow requests, so the general user is unable to access the system because it is working at its limits. The standard way to prevent it is the implementation of lockout (prevents making a certain number of requests from a single IP) or progressive delay (adds delay longer than previous after each bad request). The good practice is to set a max timeout per each request so it. There are a lot of libraries for all popular frameworks. Or the better solution is to run load-balancer like Nginx to </span><a href="https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus/"><span style="font-weight: 400;">Nginx advices</span></a></p>
<p><span style="font-weight: 400;">Distributed denial of service attack is one that is hard to overcome without side-party solutions. The traffic comes from a bunch of sources that makes it impossible to stop it by simply blocking sources. </span></p>
<ul>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">A good idea to partly prevent it is to use a </span><a href="https://en.wikipedia.org/wiki/Content_delivery_network"><span style="font-weight: 400;">content delivery network</span></a><span style="font-weight: 400;">, where servers are located in different places and combined in a single network. So the user will access the nearest server. </span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Another simple idea is to provide a captcha for anonymous requests.</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">You can use services like </span><a href="https://www.cloudflare.com/"><span style="font-weight: 400;">Cloudflare </span></a><span style="font-weight: 400;">or </span><a href="https://www.imperva.com/?redirect=Incapsula"><span style="font-weight: 400;">Incapsula </span></a><span style="font-weight: 400;">that are good-protected from it.</span></li>
<li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Use Azure/AWS gateways or virtual networks with built-in DDOS protection</span></li>
</ul>
<h2><span style="font-weight: 400;">Tests</span></h2>
<p><span style="font-weight: 400;">It is awesome to implement all these recommendations in your project. But during the development process, many things can be changed, after fixing issues, already working logic may break. So it is very important to have security tests. You should create integration tests that should cover not only positive cases but also check if users don’t have permission to do some data manipulations. Very important to cover all requests.</span></p>
<p><span style="font-weight: 400;">Also, there are more technologies to help find security pitfalls, the two most popular are SAST and DAST.</span></p>
<p><a href="https://owasp.org/www-community/Source_Code_Analysis_Tools"><span style="font-weight: 400;">Static Application Security Testing (SAST)</span></a><span style="font-weight: 400;">: the main idea is to check source code and find security vulnerabilities. Tools that use this technique find the patterns or rules in source code that can lead to flaws. This approach can be used in any stage of the development process; some tools analyze code even in IDE.</span></p>
<p><a href="https://owasp.org/www-community/Vulnerability_Scanning_Tools"><span style="font-weight: 400;">Dynamic application security testing (DAST)</span></a><span style="font-weight: 400;">: here we know nothing about source code, we just try to execute attacks and check what is going wrong. DAST tools allow detecting vulnerabilities with minimal user interactions to detect a lot of runtime and configuration security vulnerabilities.</span></p>
<p><span style="font-weight: 400;">Don’t forget about stress-tests attacks. There are a bunch of open-source tools to check the performance of your application and how many users it can process. One of such tools is </span><a href="https://jmeter.apache.org/"><span style="font-weight: 400;">JMeter</span></a><span style="font-weight: 400;">. It has a simple GUI where you can configure multiple scenarios for different routes from multiple threads. </span></p>
<p><img class="wp-image-19881 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/7-300x161.jpg" alt="" width="501" height="269" srcset="https://binary-studio.com/wp-content/uploads/2021/08/7-300x161.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/7.jpg 456w" sizes="(max-width: 501px) 100vw, 501px" /></p>
<p><span style="font-weight: 400;">It shows all responses during the test that will be useful for debugging. Also, it is possible to generate a report with statistics etc.</span></p>
<p><img class="wp-image-19880 aligncenter" src="//binary-studio.com/wp-content/uploads/2021/08/8-300x138.jpg" alt="" width="563" height="259" srcset="https://binary-studio.com/wp-content/uploads/2021/08/8-300x138.jpg 300w, https://binary-studio.com/wp-content/uploads/2021/08/8.jpg 512w" sizes="(max-width: 563px) 100vw, 563px" /></p>
<h2><span style="font-weight: 400;">Conclusion</span></h2>
<p><span style="font-weight: 400;">Your API service is the communication center in your application. It should be like a castle on a hill inaccessible on all sides. Of course, implementation of new features is very important but losing the private data of your users or any sensitive info of the company is the last thing you want to deal with. So it is important to allocate time for writing integration tests and configuring SAST and DAST tools. </span></p>
<p>The post <a rel="nofollow" href="https://binary-studio.com/2021/08/28/how-to-secure-your-rest-api-service/">How to secure your REST API service?</a> appeared first on <a rel="nofollow" href="https://binary-studio.com">Offshore Custom Software Development Company | Binary Studio, Ukraine</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://binary-studio.com/2021/08/28/how-to-secure-your-rest-api-service/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
