<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Oleg Gulevskyy]]></title><description><![CDATA[Oleg Gulevskyy]]></description><link>https://blog.oleggulevskyy.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 16 Sep 2026 22:09:03 GMT</lastBuildDate><atom:link href="https://blog.oleggulevskyy.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Navigate and Contribute to a New Codebase Efficiently]]></title><description><![CDATA[If you are new to the programming world, you might have been there - you are finally starting to work on a real world, production project, that actually has users. You grinded your skills with YouTube videos and putting together a bunch of bootcamp p...]]></description><link>https://blog.oleggulevskyy.dev/how-to-navigate-and-contribute-to-a-new-codebase-efficiently</link><guid isPermaLink="true">https://blog.oleggulevskyy.dev/how-to-navigate-and-contribute-to-a-new-codebase-efficiently</guid><category><![CDATA[Beginner Developers]]></category><category><![CDATA[#codenewbies]]></category><category><![CDATA[code]]></category><category><![CDATA[Career]]></category><dc:creator><![CDATA[Oleg Gulevskyy]]></dc:creator><pubDate>Wed, 24 Jul 2024 14:21:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721831564863/78e158cd-a456-4bd7-b410-80ffe8122a80.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you are new to the programming world, you might have been there - you are finally starting to work on a real world, production project, that actually has users. You grinded your skills with YouTube videos and putting together a bunch of bootcamp projects, but this one is a bit different. It's not a project you wrote from ground up, it has its own history, tools (that might not be the same as you are used to) and purpose.</p>
<p>I remember my first project was a bit daunting in this regard. I was completely lost and was afraid to look unprepared or too incompetent to ask questions.</p>
<p>So, to help you overcome this here is my list of things I usually do when I start on a new project / codebase.</p>
<h2 id="heading-1-assess-the-projects-structure">1. 🔎 Assess the project's structure</h2>
<p>Regardless of what you are working on, frontend, backend, devops etc in a project you will always have <strong>specific file / folder</strong> structure. <strong>Specific tools</strong> being in use to format, lint validate, build, deploy, preview the code etc. There will be specific <strong>naming and organisation conventions</strong> (or a lack of them).</p>
<p>More often than not, you can study this right at the doorstep of the project. Take a good look at the project's main file containing dependencies (for JS users - <code>package.json</code> for example). Surf through the files and direcotries to understand how features are broke down.</p>
<h2 id="heading-2-launch-the-project-locally">2. 🏎️ Launch the project locally</h2>
<p>Regardless if it's a website, a server, plugin or a driver - if you plan to work on it, you will most likely need to build it locally. So, do this then.</p>
<p>Now that you have an idea what kind of tools are being used in the project, second order of the business is to try to run the project locally. It might be as simple as running <code>npm run dev</code> (or alternative command), or might be something more complicated, with different dependencies for different operating systems, installing additional software etc (which you should be aware of from the first step - if not, you will inevitably get hints in forms of errors on what is lacking on your machine).</p>
<p>One thing I find common between different projects - <strong>lack of documentation around different environment variables</strong>. More often than not you will different environment variables containing some configurations, secrets etc. Sometimes they are not properly documented and the consequences of missing them out when starting the project can sometimes be not very obvious. Keep it in mind.</p>
<h2 id="heading-3-a-small-change">3. ✍️ A small change</h2>
<p>You have a good idea what tools are being used. You launched the project. You feel like nothing can stop you now. Wait. Do not try to conquer the world... just yet.</p>
<p>Start small - take a small request to change (pick an issue, or, if you are in a professional environment, one will be assigned to you most likely) and dig from there.</p>
<p>Here is a <strong>very concrete example</strong>, you need to change that alert notification text and how much it is displayed on the main page.</p>
<p>Identify potentially static parts of this alert (something that does not change based on X scenario and always remains the same), like a text. Try to find this text inside the project by searching globally over the project. Find the responsible component or a feature that produces this text. Most likely, you will have some logic around it - some timing, some constructors, translations etc.</p>
<p>Even if you cannot find the specific text, take a neighbour text, something that lives pretty close to what you need to change, and search for it. Most likely, you will find them residing side by side.</p>
<p>Pay good attention at why you found this text where you found, how the file is called, why is it being there. What does it interact with and what relies on it. I call it - context scanning. You have a chance to scan the context around something and see how things are working, even if it is just a text and a button.</p>
<h2 id="heading-4-check-existing-open-pull-requests">4. 💅 Check existing / open pull requests</h2>
<p>This step can be done outside of the order of these advices as it is more of a "keep your head above the water" advice. It is good to know what your teammates are doing, how do people leave review (identify who is the most mean person in the wild west and get reviews only from them), what kind of features are being prepared and what kind of files are being modified for it to work.</p>
<h2 id="heading-5-ask-questions">5. 🙋 Ask questions</h2>
<p>More often than not, you will have someone to help you and to answer your questions. Sometimes very available person, sometimes not at all or almost not.</p>
<p>In any case, be ready to ask questions. Asking questions about the project, structure, where to start or what might be potentially affected is never a stupid idea. In fact, it is considered as a good thing - you don't want to mess things up. Just make sure you tried to steps above, tried to find the answers yourself. If you feel like it is specific to the project and does not have an obvious and straight forward answer -ask away.</p>
<h3 id="heading-et-voila">Et voila 🥖</h3>
<p>I got those steps by starting on many new projects and it kind of became a habit that I use now on every new project I start on.</p>
<p><strong>Hoping this helps and bon courage</strong>!</p>
]]></content:encoded></item><item><title><![CDATA[Simple Steps for Including Custom Fields in Wasp Google Auth]]></title><description><![CDATA[The problem statement
When using Google OAuth in Wasp project, you might notice that behind the scenes, whenever you are logging in the user, creates the user for you, if it doesn't exist. It does so with very minimal user fields, but what if you nee...]]></description><link>https://blog.oleggulevskyy.dev/simple-steps-for-including-custom-fields-in-wasp-google-auth</link><guid isPermaLink="true">https://blog.oleggulevskyy.dev/simple-steps-for-including-custom-fields-in-wasp-google-auth</guid><category><![CDATA[Wasp]]></category><category><![CDATA[fullstack]]></category><category><![CDATA[google Oauth]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Oleg Gulevskyy]]></dc:creator><pubDate>Sun, 23 Apr 2023 19:55:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682280108174/177f1320-9762-445f-862a-e4aabb337994.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-the-problem-statement">The problem statement</h2>
<p>When using Google OAuth in <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> project, you might notice that behind the scenes, whenever you are logging in the user, creates the user for you, if it doesn't exist. It does so with very minimal user fields, but what if you need additional user information, such as <code>profile image</code> or <code>full name</code>?</p>
<p>Let's take care of that and learn a thing or two about <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> lang.</p>
<h2 id="heading-the-solution">The solution</h2>
<ol>
<li>Make sure your database has the correct columns, in the User table. In my case, I added 2 more properties to the User entity, in my <code>main.wasp</code> file:</li>
</ol>
<pre><code class="lang-pgsql">entity <span class="hljs-keyword">User</span> {=psl
  id                        <span class="hljs-type">Int</span>             @id @<span class="hljs-keyword">default</span>(autoincrement())
  email                     String?          @<span class="hljs-keyword">unique</span>
  <span class="hljs-keyword">password</span>                  String?
  isEmailVerified           <span class="hljs-type">Boolean</span>         @<span class="hljs-keyword">default</span>(<span class="hljs-keyword">false</span>)
  emailVerificationSentAt   DateTime?
  passwordResetSentAt       DateTime?
    profileImage                            String?
    fullName                                    String?
  stripeId                  String? 
  checkoutSessionId         String?
  hasPaid                   <span class="hljs-type">Boolean</span>         @<span class="hljs-keyword">default</span>(<span class="hljs-keyword">false</span>)
  sendEmail                 <span class="hljs-type">Boolean</span>         @<span class="hljs-keyword">default</span>(<span class="hljs-keyword">false</span>)
  datePaid                  DateTime?
  credits                   <span class="hljs-type">Int</span>             @<span class="hljs-keyword">default</span>(<span class="hljs-number">3</span>)
  relatedObject             RelatedObject[]
  externalAuthAssociations  SocialLogin[]
psl=}
</code></pre>
<p>Once added, run <code>wasp db migrate-dev</code> so <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> takes care of all the db migrations, and relaunch your server.</p>
<ol>
<li>In <code>main.wasp</code> add a new dependency <code>@types/passport-google-oauth20</code>. At the time of writing this article, the actual version is <code>2.0.11</code> but go ahead and install the latest one.</li>
</ol>
<pre><code class="lang-cpp">(<span class="hljs-string">"@types/passport-google-oauth20"</span>, <span class="hljs-string">"2.0.11"</span>)
</code></pre>
<p><em>The reason why you install</em> <code>@types/passport-google-oauth20</code> <em>is because <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> is using</em> <code>passport</code> <em>to handle authentication strategy etc behind the scenes, so that's exactly the types that are used in the backend and that you can expect to be returned.</em></p>
<ol>
<li><p>Create a file under <code>src/server/auth/google.ts</code></p>
</li>
<li><p>Add new function <code>getUserFields</code> alongside with type import:</p>
</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Profile } <span class="hljs-keyword">from</span> <span class="hljs-string">"passport-google-oauth20"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserFields</span>(<span class="hljs-params">
  _: unknown,
  args: { profile: Profile }
</span>) </span>{
  <span class="hljs-keyword">const</span> userFields = {
    email: args.profile._json.email,
    profileImage: args.profile._json.picture,
    fullName: args.profile._json.name,
  };
  <span class="hljs-keyword">return</span> userFields;
}
</code></pre>
<ol>
<li>Declare your <code>getUserFields</code> function in <code>main.wasp</code> file, by adding <code>getUserFieldsFn</code> property to <code>auth.methods.google</code> object, like so:</li>
</ol>
<pre><code class="lang-typescript">  auth: {
    userEntity: User,
    externalAuthEntity: SocialLogin,
    methods: {
      google: {
        getUserFieldsFn: <span class="hljs-keyword">import</span> { getUserFields } <span class="hljs-keyword">from</span> <span class="hljs-string">"@server/auth/google.js"</span>, <span class="hljs-comment">// &lt;-- add `getUserFieldsFn` property</span>
        configFn: <span class="hljs-keyword">import</span> { config } <span class="hljs-keyword">from</span> <span class="hljs-string">"@server/auth/google.js"</span>,
      },
    },
    onAuthFailedRedirectTo: <span class="hljs-string">"/"</span>,
  },
</code></pre>
<p><a target="_blank" href="https://wasp-lang.dev/docs/language/features#getuserfieldsfn">Function <code>getUserFields</code> is a special function</a>, that <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> is using to retrieve any user fields that will be added to the database. The second argument of this function is to receive an object, that contains <code>profile</code> of type <code>Profile</code> . This is what is being "passed" to you by <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> , so that you can "cherry-pick" what you want to be saved into your User record when one will be created.</p>
<p>Whatever object you will return from this function, this is what will be stored in the User table, under the new row. As you can see, I am retrieving <code>profileImage</code> and <code>fullName</code> properties from <code>args.profile._json.</code> object.</p>
<p>You can read more about <code>getUserFields</code> in the linked article, but it's only covering <code>JavaScript</code> file, not TypeScript, so hoping this article helps you to annotate. your codebase better, until <a class="user-mention" href="https://hashnode.com/@Wasp-Lang">Wasp</a> provides you with a type export by itself.</p>
<p>Follow me here on 📖 Hashnode: <a target="_blank" href="https://blog.oleggulevskyy.dev/">https://blog.oleggulevskyy.dev/</a></p>
<p>Follow me on 🐦 Twitter: <a target="_blank" href="https://twitter.com/preacher_rourke">https://twitter.com/preacher_rourke</a></p>
<p><strong>I am sharing all the cool stuff I find, daily.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Discovering the Zed IDE: An Overview]]></title><description><![CDATA[What is Zed?
Zed is a new kid on the block in the IDE business but seems to be causing some people to talk about it.
https://twitter.com/adamwathan/status/1648867721944104960?s=20
 
From the first look, it appears to be focusing on blazing speed (jus...]]></description><link>https://blog.oleggulevskyy.dev/discovering-the-zed-ide-an-overview</link><guid isPermaLink="true">https://blog.oleggulevskyy.dev/discovering-the-zed-ide-an-overview</guid><category><![CDATA[IDEs]]></category><category><![CDATA[vim]]></category><category><![CDATA[neovim]]></category><category><![CDATA[vscode]]></category><category><![CDATA[Zed]]></category><dc:creator><![CDATA[Oleg Gulevskyy]]></dc:creator><pubDate>Fri, 21 Apr 2023 12:23:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682079599743/7d563b5d-5b69-4e16-b875-2a6ac7b96eff.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-zed">What is Zed?</h2>
<p>Zed is a new kid on the block in the IDE business but seems to be causing some people to talk about it.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/adamwathan/status/1648867721944104960?s=20">https://twitter.com/adamwathan/status/1648867721944104960?s=20</a></div>
<p> </p>
<p>From the first look, it appears to be focusing on blazing speed (<em>just like everything with Rust</em>) and shareability.</p>
<p>While the speed is evident, what does "shareability" mean? The Zed development team frequently promotes this feature - the capability to share projects with your peers by inviting them to a live session. In this session, you can track each other's cursors and engage in pair programming or any other text editing tasks together.</p>
<h2 id="heading-ui">UI</h2>
<p>This is one thing I am pretty fond of - their UI is very, very, I mean very minimal. I come to like this kind of thing lately, and for this - UI is very attractive.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078132176/8f37db10-9e50-4b6d-89e5-0719415f260c.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078149316/90836ee9-4c60-4116-a302-050b07d23c4f.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078163800/ea2bc07f-f025-46e2-95dd-12276491414b.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078204060/9ba82026-286c-448e-90f4-99eb030bddf6.png" alt class="image--center mx-auto" /></p>
<p>And this is their default UI theme. What's not to like? Taking my hat off here. But if you think this is too grim for you, you can treat yourself to any other theme, that comes baked into Zed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078307109/fb3f6da0-6e65-47e5-8db3-b9638a36ad58.png" alt class="image--center mx-auto" /></p>
<p>Worth noting, whenever you scroll the Theme from the selection - it immediately applies to the entire editor, giving you a good preview.</p>
<p>Sweet, what's next?</p>
<h2 id="heading-speed">Speed</h2>
<p>I mean goddaymn, this seems to be fast. I smell Rust all over it. Even the fact that you can preview the theme on the fly just by going Up and Down on the Theme picker - says a lot about the snappiness of the editor.</p>
<p>However, I also think that the fact that there are no plugins (in my current setup) installed plays a huge factor - nothing blocks the main boot process, no additional operations happen when I open files etc. It's just Rust window and LSP (<a target="_blank" href="https://microsoft.github.io/language-server-protocol/">Language Server Protocol</a>)</p>
<h2 id="heading-user-experience">User Experience</h2>
<p>Well, this one is very very subjective, and I review it from a point of a "lazy and stubborn user" (which I might relate to) so take it with a handful spoon of salt.</p>
<p>First of all, I love their command palette. It's just visually appealing, and snappy (both points above) and seems to be aiming for a variety of options to choose from. Even some Vim commands. However, when I tried to use one of those options, such as <code>vim: quotes</code>, Zed died on me instantly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078722335/fbff2d43-745a-4a0c-ab77-31a1605f0b58.png" alt class="image--center mx-auto" /></p>
<p>I don't even know what this command was supposed to do and was curious to use it. However, after restarting it, it does not crash anymore, nor does it do anything.</p>
<p>Anyway, using something a bit more "traditional" brings the desired result, and does it so fast.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682078837561/0f086547-1aed-4937-acc0-d30496f1952c.png" alt class="image--center mx-auto" /></p>
<p>Some things appear to be working out of the box, which is the most important thing IMHO when it comes to IDE, such as LSP.</p>
<p>But I do wonder, if someone will ever be able to focus on TypeScript errors formatting and offer this on a native level, rather than some extension/plugin.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682079192568/0782cfb4-7176-41c2-bf28-5bc0a141c11e.png" alt class="image--center mx-auto" /></p>
<p>This is not against Zed, but I would be very excited to see this handled one day.</p>
<h2 id="heading-what-about-vim">What about Vim?</h2>
<p>It claims that it supports Vim and it appears to be in the very early stage, but from what I saw - I was able to use only basic operations/navigations through the document, but having to move from Neovim, I was practically a "turtle" when it comes to navigation. A big chunk of functionality is just not there, or it's not clear how to "enable" it. I.e. navigating from the opening bracket to the closing bracket <code>Shift + 5</code> or Jumping on empty lines - <code>Cmd + Shift + { / }</code> . So while you can edit words in Vim mode, you can't do much more than that, just yet.</p>
<h2 id="heading-overall">Overall</h2>
<p>I am excited about it, mainly because of the simplicity, elegance and speed that it brings to the game, but being an avid Vim user, the IDE is not usable to me at least at this stage. I would be curious to see what others think of it, especially users of VSCode, Fleet, WebStorm etc, but if you are used to some plugins heavy activity, where you have tons of different plugins doing the heavy lifting for you, this might not be your poison. But do give it a try!</p>
]]></content:encoded></item><item><title><![CDATA[Warp - terminal reimagined]]></title><description><![CDATA[Terminals - powerful things. If you know how to operate a terminal - you know how to manage your machine in ways that others (non-terminals) don't. I am not going to dive deep into UI vs terminal, but I will, however, share my excitement about a tool...]]></description><link>https://blog.oleggulevskyy.dev/warp-terminal-reimagined</link><guid isPermaLink="true">https://blog.oleggulevskyy.dev/warp-terminal-reimagined</guid><category><![CDATA[Productivity]]></category><category><![CDATA[terminal]]></category><category><![CDATA[Warp]]></category><category><![CDATA[macOS]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Oleg Gulevskyy]]></dc:creator><pubDate>Wed, 19 Apr 2023 07:52:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654446787318/uEMqyEDui.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Terminals - powerful things. If you know how to operate a terminal - you know how to manage your machine in ways that others (<em>non-terminals</em>) don't. I am not going to dive deep into <strong>UI vs terminal</strong>, but I will, however, share my excitement about a tool that I came across recently - <a target="_blank" href="https://www.warp.dev/"><strong>Warp</strong></a>.</p>
<p>To me - managing a terminal can be awkward, especially if you are just dipping your toes into <em>terminal-like</em> life for the first time. Warp makes it easy. (btw, I am not paid or affiliated with Warp in any way - this is my real excitement and experience with it)</p>
<p>Each command is based on blocks, which in itself allows you to do different things with them:</p>
<ul>
<li><p>Copy command</p>
</li>
<li><p>Copy output</p>
</li>
<li><p>Find within a block (searching text inside the result of each command, instead of a whole terminal window)</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654447220241/j6h4HfolQ.png" alt="image.png" /></p>
<ul>
<li>And some other useful things, that I leave to you to find out... :)</li>
</ul>
<h2 id="heading-list-of-my-four-favorite-things-so-far">List of my four favorite things so far</h2>
<h2 id="heading-speed">Speed</h2>
<p>It is fast. Like, native fast. The terminal is done in Rust and you can <a target="_blank" href="https://www.warp.dev/blog/how-warp-works">read more about it here</a>, team behind Warp publishes a fantastic read about the ideology and goals within it. Working with it feels very snappy, with <strong><em>blazingly</em></strong> (yeah, I know you might have saw adjective <em>blazingly</em> everywhere by now) fast response and fast scroll-through. I notice fast scroll-through on purpose, because for me - having M1 Mac and some medium-sized output in the VSCode terminal makes the scrolling experience very painful, with freezes on scrolling. Not a thing anymore with Warp.</p>
<h3 id="heading-accessibility">Accessibility</h3>
<p>One of my favorite things - access Warp at any place, any time. Warp allows you to have a "global" shortcut key, that opens it up regardless of what you are doing. Warp is constantly running my servers now, where I can open output at any given time and check how things are in my garden.</p>
<p>Give it a go, and search for - <strong>Global hotkey</strong> settings, in the <strong>Features</strong> tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681888942827/cbf313a2-e2fc-4d10-b662-86c49717f826.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-ui">UI</h2>
<p>Simple and done with good taste. It comes with prebuilt themes (dark and light) for you to select from, or should you feel expressive enough - you can create your themes. Let me know if that's something that would interest you and I will craft one artisanal, just for you.</p>
<h3 id="heading-workflows">Workflows</h3>
<p>Create your kind of "templates" or presets, that you can find by description and reuse at any time. More about this some other time, but do let me know if that's something you would be interested in and I will craft another article just for this.</p>
<h3 id="heading-input-experience">Input experience</h3>
<p>The input itself is just a regular text editor. No more "struggles" on how to move cursours from one place to another. If you ever typed text in a simple text area - you will do just fine in Warp.</p>
<h3 id="heading-ai">AI</h3>
<p>A thing that buzzes everywhere now, but it AI in Warp has a simple but noble goal to do:</p>
<ul>
<li><p>Remind you of a command you might have forgotten</p>
</li>
<li><p>Explain a command in case you are not sure what it does</p>
</li>
<li><p>Suggest you a command for a use case you need</p>
</li>
</ul>
<p>I no longer google stuff like "<em>how to remove a file from git tracking</em>" or "<em>how to replace a text in a string and save it to a file</em>". Everything is available to me in my own editor.</p>
<p>And guess what - I am not paying for it, this is all for free.</p>
<p>However, if you do decide to try and this article was helpful, you can always use my referral link, that supposed to give me more nice themes :)</p>
<p><a target="_blank" href="https://app.warp.dev/referral/2VRWJE">https://app.warp.dev/referral/2VRWJE</a></p>
<p><em>Then, it will be your turn to give away referrals...</em></p>
]]></content:encoded></item><item><title><![CDATA[Wasp Configuration Language: Simplify Full Stack App Creation]]></title><description><![CDATA[What is Wasp?
Imagine modern monorepos. If you are not using typesafe solutions like tRPC , chances are - you know the pain of synchronizing your types between the backend and front end.
More than that - you are probably also aware that creating new ...]]></description><link>https://blog.oleggulevskyy.dev/wasp-configuration-language-simplify-full-stack-app-creation</link><guid isPermaLink="true">https://blog.oleggulevskyy.dev/wasp-configuration-language-simplify-full-stack-app-creation</guid><category><![CDATA[full stack]]></category><category><![CDATA[Full Stack Development]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[typesafe]]></category><dc:creator><![CDATA[Oleg Gulevskyy]]></dc:creator><pubDate>Tue, 18 Apr 2023 18:55:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/LTECPlcp3Xc/upload/5360b05f195fe4d988c322796a52409d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-what-is-wasp">What is Wasp?</h3>
<p>Imagine modern monorepos. If you are not using typesafe solutions like <code>tRPC</code> , chances are - you know the pain of synchronizing your types between the backend and front end.</p>
<p>More than that - you are probably also aware that creating new projects, endpoints, databases, scaffolding frontend, and backend is somewhat simplified nowadays compared to what it was 2-3 years ago, but still - one of the most tedious tasks there is. I for one am not interested in repeating the same thing I do for different projects. <strong>I want to write logic, I want to create products.</strong></p>
<p>So, you can either turn to some pre-built by someone boilerplate, that either is open source and more often than not crappy and outdated, or a paid one, that is actively maintained but pricey. And even after that, it will be like learning a completely new codebase, to get the grip of the boilerplate ropes.</p>
<p>So what then, CLI, to scaffold our boilerplate? <a target="_blank" href="https://create.t3.gg/">Something like T3</a>? You could, but it's serverless stuff, that you might not necessarily need/want. What if you need a fully functioning backend + frontend?</p>
<p>Hold the door: here comes in <a target="_blank" href="https://wasp-lang.dev/">Wasp</a> - it's neither of those options listed above, but provides you with way more than just a boilerplate.</p>
<p><strong>Wasp - is a configuration language</strong>, it's not a programming language. If you learned how to read the all-mighty JSON, you will be most likely able to grasp Wasp. I did - it means anyone can.</p>
<p>Ultimately, you create a file <code>.wasp</code> and tell Wasp compiler:</p>
<ol>
<li><p>what kind of endpoints you need, what they do (read or write);</p>
</li>
<li><p>what your database should look like</p>
</li>
<li><p>what your frontend routes should look like</p>
</li>
<li><p>what authentication methods do you want to use</p>
</li>
</ol>
<p>...and hit the command in your terminal to generate a project, that does exactly that:</p>
<ul>
<li><p>have all the stuff you need to be generated for you in a clear, unobfuscated way (you can navigate yourself in the generate output folder even)</p>
</li>
<li><p>creates a database for you</p>
</li>
<li><p>handles migrations</p>
</li>
<li><p>makes sure your frontend knows your backend types (full-stack type safety)</p>
</li>
<li><p>and many more things, that I have yet to discover myself!</p>
</li>
</ul>
<p>Pretty neat project structure, from the get-go</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681843600657/4584d219-ed45-4929-95a7-de424ad6fa7a.png" alt class="image--center mx-auto" /></p>
<p>Now that I am done selling it, let me tell you my initial thoughts about it and the project overall.</p>
<h3 id="heading-initial-feeling">Initial feeling</h3>
<p>I love engineering, new ideas, new projects and things related to DX. I find it pretty important to have good DX for the quality of the product's life (whatever product this is). If you have an excellent product but shitty, legacy code, that does not scale or is just a nightmare to maintain you are almost guaranteed to have trouble finding the right people to work on it (you will find people, but they will leave one way or another). Welp, that's just my belief, does not necessarily make it right.</p>
<p>This brings me to the point, that what Wasp seems to be aiming for is to gap the bridge backend and front, where anyone even with a minimum of experience in both fields can create full-stack apps. It spins up a nodejs server for you and handles DB connection, migrations, and data modeling (to a certain level of course). So, the goal is noble but I only have one fear - abstraction. Nowadays all our technology is abstracting so much from the basics (which is expected), that new people coming into the field can achieve the same projects/goals but have no idea how things work under the hood.</p>
<p>Abstraction simplifies development, but it also puts you in a very tricky position if things go wrong. And, you are no longer in control of your codebase/project. You depend on yet another tool, for this tool to do well and do the job correctly. If tomorrow there is a bug that nobody caught in this tool - your end users will be affected.</p>
<h3 id="heading-getting-started">Getting started</h3>
<p>Abstraction is one thing, but I like shiny new tools and this seems intriguing, so I jump over to the documentation "Get started" section.</p>
<p>All is clear until the Listing tasks, as it doesn't matter which language you are choosing for your app (JS vs TS)</p>
<p>As my choice is TS, when working on Listing tasks, the article only focuses on JS (which it says in its title, so no blame). But, I think that TS is a very important piece of info to include, so I was expecting the very same implementation shown in the same article, but in TS also. Instead, I had to find a "<a target="_blank" href="https://discord.com/channels/686873244791210014/1097914579880783995/1098159771204468766">TypeScript support</a>" separated where it is written how to implement this using TS. The example given in the TS article also derails from the JS article (focuses on plural tasks vs singular) so it's a bit confusing and hard to grasp at first.</p>
<p>Because really, the only difference between JS and TS implementations is one extra import statement:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { GetTasks } <span class="hljs-keyword">from</span> <span class="hljs-string">"@wasp/queries/types"</span>
</code></pre>
<p>...and annotate the function with the type like so:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getTasks: GetTasks = <span class="hljs-keyword">async</span> (args, context) =&gt; { 
    <span class="hljs-keyword">return</span> context.entities.Task.find <span class="hljs-built_in">any</span>();
};
</code></pre>
<p>Hence, I think it deserves a life in the same article :)</p>
<h3 id="heading-hard-to-debug">Hard to debug</h3>
<p>When transitioned into listing tasks in React component, I encountered an error where TS could not find my <code>getTasks</code> declaration.</p>
<p><img src="https://firebasestorage.googleapis.com/v0/b/reflect-prod.appspot.com/o/users%2F8ZrzGnPDj9RmzJJnFApclKKfkk13%2F33123cfe439a4878a05fee7df7067cb4?alt=media&amp;token=21a6cb76-1933-4b55-8ddb-652605526bd3" alt /></p>
<p>Not only do I have no idea why this default export seems to be missing, but I can't also find the package <code>/queries/*</code> to try to debug it (see if the file has been generated or not), and that's because my IDE is not able to <code>Go To Definition</code>, while I can't find <code>@wasp</code> package manually (in the <code>.wasp</code> folder, in the <code>src</code> folder).</p>
<p>In the end, I managed to find the folder where queries are being imported from, but no file in question, so had to turn to the community for help.</p>
<p>With help of the community (a dev and devrel, I believe) we managed to pin down what was happening and fix the issue. So just to be clear, my issue here is not with the bug itself, as this is just an implementation detail and I was trying to do <strong>weird</strong> things (like install react 18) but with the abstraction itself, which complicates the experience in case things go south.</p>
<p><em>And I am not sure if it's my LSP that messes up with me or something else entirely, but my LSP rarely messes with me, so I gave it a credit of trust and blamed abstraction.</em></p>
<h3 id="heading-community">Community</h3>
<p>The guys are great, helpful, replying to questions openly and pretty fast. One of the guys ( @Vinny ) offered to jump on the call with me and the issue I had was resolved very fast, so that's dope! I can't stress enough how important it is to have good/proper relationships with your end user (via any way possible - support, account manager etc).</p>
<p>In this case, even if I am skeptical about the entire thing and I have hiccups on the way to what the project offers, I know that a bunch of people have got my back and are ready to jump on the call with me to resolve this straight away. Whereas, if I try another project/product, that offers the same or alternative idea, the chances are - I will just abandon the thing from the get-go and get back to the traditional way of building things.</p>
<h3 id="heading-overall">Overall</h3>
<ul>
<li><p>By the time I reach the chapter on Updating the list, I find myself enjoying the simple experience there is. Especially I liked the fact that the query from the client side is automatically invalidated by the Wasp, therefore the data on the creation of new tasks updated itself automatically. This was unexpected but I didn't know I wanted this until I saw it 🙂 There seems to be a conversation about this topic, where the dev team wants to allow overriding this behavior which I can see the importance of, but - it just worked.</p>
</li>
<li><p>It is dammmn fast. Like, the start and stop of the server are snappy, and the commands are fast. The client-side changes do take some time to refresh, and I wonder if this scales with the app, but the initial "behind the scenes" stuff seems to be fast. And again, the experience of creating different "endpoints" and functionality helps us move faster. Some cool <code>tRPC</code> stuff right there.</p>
</li>
<li><p>Excited to try this out in a real project rather than a to-do list... just need to carve out some time for it to start. :D</p>
</li>
</ul>
<h3 id="heading-next">Next</h3>
<p>I have an idea that I would love to try Wasp out for, as it seems like a good fit for it. Initially, I wanted to use NextJS with tRPC for it, but it didn't go as planned (mainly because of Nextjs) due to how Google Auth works inside iframed applications (it just doesn't). So, I hope that more of a client-side authentication will be possible (like it's very easy with Firebase). This is where I will have a chance to try more authentication in Wasp, sending emails and deploying. 🤞</p>
]]></content:encoded></item><item><title><![CDATA[Wails - You don't need CLIs anymore]]></title><description><![CDATA[I am a big fan of productivity tools and automating stuff.
A company where I work started the migration process from Zendesk Help Center (it's where all our documentation is hosted) to React based Docusaurus.
Big challenge that they faced is to migra...]]></description><link>https://blog.oleggulevskyy.dev/wails-you-dont-need-clis-anymore</link><guid isPermaLink="true">https://blog.oleggulevskyy.dev/wails-you-dont-need-clis-anymore</guid><category><![CDATA[wails]]></category><category><![CDATA[desktop apps]]></category><category><![CDATA[Go Language]]></category><dc:creator><![CDATA[Oleg Gulevskyy]]></dc:creator><pubDate>Sun, 13 Nov 2022 15:07:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668351938054/EEpsISPmG.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I am a big fan of productivity tools and automating stuff.</p>
<p>A company where I work started the migration process from Zendesk Help Center (it's where all our documentation is hosted) to React based Docusaurus.
Big challenge that they faced is to migrate all of HTML-based articles to Markdown. In addition to that - each Markdown file has to be of <code>.mdx</code> file format (which would allow. them to import assets, components and all that kind of good stuff that you usually use nowadays).</p>
<p>Sounds like a good place for a CLI tool, right? - that's what I thought.</p>
<h2 id="heading-preparation">Preparation</h2>
<p>There is not much to it really, so I will be quick. </p>
<ol>
<li><strong>Get all the data needed somewhere</strong> - which is in my case, a list of all articles that our documentation team wanted to migrate. </li>
</ol>
<p>For that, I decided to export all the articles data from Zendesk Help Center into Google Spreadsheet. If you ever find yourself in the same position - use <a target="_blank" href="https://awesome-table.com/connectors">Awesome Table Connector addon</a>, it's a seriously helpful tool.</p>
<ol>
<li>Decide on which programming language to choose from.
There are only 2 languages in my belt (for now) I can choose from - JS or Go. But, I do prefer Go, so the choice here was obvious. And, as I soon will find out this was the right choice.</li>
</ol>
<h2 id="heading-cli-tool">CLI Tool</h2>
<p>Now that I have my data and chose the language, my CLI tool was fairly simple:</p>
<ul>
<li>With help of Google Service accounts, fetch list of HTML bodies from prepared Google Spreadsheet</li>
<li>Transform each HTML body into a Markdown file, where the <a target="_blank" href="https://pkg.go.dev/github.com/JohannesKaufmann/html-to-markdown">html-to-markdown</a> package does all the heavy lifting.</li>
<li>In the process of transforming, collect all the images and their URLs from <code>&lt;img src=".." /&gt;</code> tags and download them. Had to be extra careful here though, as I am big fan of Go and its <strong>goroutines</strong> feature, making a big amount of network requests to download them (1200 image URLs) would lead to some troubles such as timeouts etc, thus it had to be batched.</li>
<li>Add imports of those images to each transformed <code>.mdx</code> file.</li>
</ul>
<h2 id="heading-first-version-result">First version result</h2>
<p>Because the tool is not for me personally, but for other teams, and the migration is an ongoing process for them, the tool cannot have hard coded values in it (such as Spreadsheet ID, for example) in order to not lose flexibility and be useful in the long run.</p>
<p>This resulted in a small handy CLI tool that did the job, that requested you to provide a Spreadsheet ID, Range where to look for and making sure you added the service account to the file's sharing list.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668350559581/9k7iS_AUc.png" alt="image.png" /></p>
<h2 id="heading-replace-cli-with-wails">Replace CLI with Wails</h2>
<p>Now, that's all nice and cool, but I remembered, absolutely randomly, that I stumbled upon a Go library called <a target="_blank" href="https://wails.io/">Wails</a>.</p>
<p>This tool is designed to give Go developers means to build native desktop apps with front-end technologies, using HTML / CSS / JS. It's aiming to be an alternative to Electron (uses NodeJS as its backend) and another famous alternative out there - <a target="_blank" href="https://tauri.app/">Tauri</a> (which uses Rust as its backend).
I am a web developer, so this sounds like an easy way to create a great UI.</p>
<p>It is truly amazing what the team behind Wails put together - intuitive API, lightweight build output (15 Mb for an application that used React + Tailwind + bundled all together to be native application). One big difference between Electron and Wails - they don't ship "browser" inside the bundle to the end-user.
Another awesome thing, that I personally love - is binding generation between your Go codebase and JS. I love type safety, and this allows me to go fast and safe, making correct calls from front-end calls to Go and having a TypeScript compiler telling me what arguments are expected and will be returned. </p>
<p>So, in order to transform my CLI into a desktop app, I went for React + Tailwind + Vite. It took me half of the day in order to move the logic from CLI to the newly desktop app powered by Wails.
And this is the result!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668351615918/tOWqhKTeB.png" alt="image.png" /></p>
<p>I think that's a pretty decent looking desktop application, compared to a boring CLI.</p>
<p>If you are interested - I'd be happy to write down the actual implementation guide in Wails, showing how you can achieve the same. Let me know :)</p>
]]></content:encoded></item></channel></rss>