<?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" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Dev In Trenches on Medium]]></title>
        <description><![CDATA[Stories by Dev In Trenches on Medium]]></description>
        <link>https://medium.com/@dev-in-trenches?source=rss-b773ad9709f6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*5SV-Nmp6D5WpuGFn6j16IQ.png</url>
            <title>Stories by Dev In Trenches on Medium</title>
            <link>https://medium.com/@dev-in-trenches?source=rss-b773ad9709f6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 27 May 2026 23:11:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@dev-in-trenches/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Cool Python Tricks To Show Off]]></title>
            <link>https://medium.com/@dev-in-trenches/cool-python-tricks-to-show-off-b0b64a88dbfd?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/b0b64a88dbfd</guid>
            <category><![CDATA[python3]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[programming-languages]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Fri, 09 May 2025 01:12:34 GMT</pubDate>
            <atom:updated>2025-05-09T01:12:34.520Z</atom:updated>
            <content:encoded><![CDATA[<h4>Know Your Python &amp; Rate Yourself 9/10 When Asked</h4><p>You may answer ”<em>I can rate myself 9/10 in Python</em>” when asked, but would that really be an honest opinion of yourself when you haven’t even stress tested Python and its design? Fret not, for I am here to show off … ahem ahem ... to guide you through what “Pythonic” actually means.</p><h3>tl;dr</h3><p>Python is highly flexible and allows some weird syntax that you normally would not expect from other languages like Java or C++. For example, as I mentioned in my previous blog <a href="https://medium.com/@hammad.ai/why-does-python-allow-print-123-c960c1035209">Why Does Python Allow “print = 123”</a>, that Python allows reassignment of built-ins and most stuff except for a few selected things like keywords which contribute to its lexical parsing inside the interpreter.</p><p>Things can get so weird with Python that any sane person would imagine that these shenanigans would throw an error but they do not. You would be right to rip your hair off and ask “WHY??”. It all boils down to the <a href="https://peps.python.org/pep-0020/">Zen of Python</a> saying “<em>Explicit is better than implicit</em>” and its design philosophy which says “<em>Everything is an object</em>”— more details on this in the blog I shared above.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jdDZYQDueu1U-Vf6" /><figcaption>Photo by <a href="https://unsplash.com/@davidclode?utm_source=medium&amp;utm_medium=referral">David Clode</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Dynamic Reassignment</h3><p>Since I talked about this above, I believe you might be curious. So let’s explore this first:</p><pre>def greet():<br>    print(&quot;Hi&quot;)<br><br>say_hello = greet  # &lt;-- your focus goes here<br>say_hello()  # output: Hi</pre><p>You just assigned a function to a variable. Not that great huh? Now look at this and tell me if it’s not <em>that great</em>.</p><pre>print(&#39;foo&#39;) # output: foo<br><br>def my_logger(*args, sep=&#39; &#39;, end=&#39;\n&#39;):<br>    with open(&#39;./logs&#39;, &#39;wa&#39;) as f:<br>        output = sep.join(str(arg) for arg in args)<br>        f.write(output + end)<br>        <br>print = my_logger<br><br>print(&#39;foo&#39;) # logs the output to a file instead of printing</pre><p>Who says you can’t use print() in production level code. But hey it is actually better if you use logging built-in library.</p><p>Do not panic if you did this. Just use the del keyword to undo the effect:</p><pre>del print # will return the print funciton to its original state</pre><p>Another usecase I wanted to share is that it can be used to create customized REPL by directly modifying the __builtins__ package.</p><pre>__builtins__.open = lambda *args, **kwargs: print(&quot;File access blocked!&quot;)<br>open(&quot;test.txt&quot;)  # File access blocked!</pre><p>❓<strong>Where it can be useful?</strong></p><ul><li>You can use it in unit testing when you need to change the behaviour of something, or when you want to test the sad flows.</li><li>When you are trying to simulate dependency injection</li><li>You can use it to wrap a function and make it work like a middleware</li><li>You can use it to load and reassign event handlers dynamically</li><li>You can partially execute a function by giving it some arguments and leaving out the other arguments before assigning it to a variable.</li><li>Building custom REPL or sandbox environments were certain functions are off-limits like os.system()which can run any command in the terminal.</li><li>And of course, monkey patching</li></ul><blockquote>📌 To be honest, there are countless things you can do with it. The list of use-cases I share at the end of each topic is not everything.</blockquote><h3>Lambdas Inside List</h3><p>lambda are anonymous function which do not need a proper definition (using def) and just need a function body to work. But these anonymous functions are itself common in most languages, but how we can use them flexibly in Python is.</p><pre>funcs = [lambda x=i: x for i in range(3)]<br>print([f() for f in funcs])  # [0, 1, 2] </pre><p>What you did up there is fill a list with lambda functions when you ran the <a href="https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions">list comprehension</a> style for loop. And then inside the print() function, you looped over that list of functions and called each one.</p><p>The above was a simple example but it can get as complex as you want it to be:</p><pre>def create_handlers(configs):<br>    handlers = []<br>    for conf in configs:<br>        handlers.append(lambda event, conf=conf: f&quot;Handler for {conf} received event {event}&quot;)<br>    return handlers<br><br>configs = [<br>  &#39;event handler 1&#39;, <br>  &#39;event handler 1&#39;, <br>  &#39;event handler 1&#39;<br>  ]<br>handlers = create_handlers(configs)<br><br># Simulate triggering events<br>for i, handler in enumerate(handlers):<br>    print(handler(f&quot;event_{i}&quot;))</pre><p>The above is an example of dynamic event handlers, where create_handlers() function takes in the names of the event handlers and uses them within a function (which is this case is a lambda function). The create_handler() function then returns a list filled with lambdas.</p><p>Note that each lambda has 2 parameters event and conf but only 1 is set as default inside each. The other parameter is to be given to it within the for loop.</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Creating button callbacks in GUIs (e.g., Tkinter or PyQt)</li><li>Generating API endpoint functions dynamically (You technically can, but would you?)</li><li>Scheduling jobs with parameterized behaviour</li><li>Binding commands to CLI options (Use subprocess package instead of os.system(). Try both and see why)</li></ul><h3>Extended Iterable Unpacking</h3><p>You may be familiar with unpacking of iterables, which is done like this:</p><pre>a, b, c = [1, 2, 3] <br><br>print(a) # 1<br>print(b) # 2<br>print(c) # 3</pre><p><em>So what kind of unholy magic can we do with it</em>, you ask?</p><p>Imagine that you have an array … erm I mean … list of too many elements. And the catch here is that you only need first few or the last few elements. The rest of the list is useless for you. I don’t know how you managed to get in this mess which screams “<em>bad code</em>” but there is a way out of it.</p><pre>first, second, third, *rest_of_the_crap, second_last, last = [i for i in range(100)]</pre><p>The *rest_of_the_crap variable contains all elements except for first, second, third, second last and last element.</p><p>That is all there is too it.</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>You can parse command line arguments and essentially separate the arguments from the main command</li><li>You can parse structured data that comes in lists like for example CSV rows.</li><li>You can use it in token trimming for Natural Language Processing (NLP)</li><li>You can de-structure logs or traces after splitting it into a list</li></ul><h3>Swapping Without Temp</h3><p>This one is also very simple but I wanted to include it anyways since not many languages are able to do it.</p><p>You can basically swap values in 2 different variables with each other without creating a temp variable.</p><p>Normally you would do this:</p><pre>a = 1<br>b = 2<br><br>print(a) # 1<br>print(b) # 2<br><br>temp = b<br><br>b = a<br>a = temp<br><br>print(a) # 2<br>print(b) # 1</pre><p>But by using Python given features you can shorten your code like this:</p><pre>a = 1<br>b = 2<br><br>print(a) # 1<br>print(b) # 2<br><br>a, b = b, a<br><br>print(a) # 2<br>print(b) # 1</pre><p>Pretty neat huh?</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Umm … anywhere you need to swap two values? It is so simple that it can be used in many places. I will leave that for your imagination.</li></ul><h3>Chained Comparisons</h3><p>Assume you have the following scenario:</p><pre>my_var = 4<br><br>if ( &#39;some conditions go here&#39; ):<br>  # you are supposed to do something here</pre><p>What you want to check in the if block is that whether the my_var is greater than 2 and less than 6 or not. So you would try something like this:</p><pre>my_var = 4<br><br>if ( my_var &gt; 2 and my_var &lt; 6):<br>  # you are supposed to do something here</pre><p>This would definitely work as intended, but there is a neat way too:</p><pre>my_var = 4<br><br>if ( 6 &gt; my_var &gt; 2):<br>  # you are supposed to do something here</pre><p>It will work as intended. Why don’t you stop taking my word for everything and try something for yourself?</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Well it is a short hand way to the lengthy stuff. Plus it is more clean.</li></ul><h3>Using &quot;else” with Things Other Than “if&quot;</h3><p>else is definitely meant for after the if keyword. But not in Python. Turns out there are many other places where you can use it.</p><p>You can use it after the for loop (what???):</p><pre>for i in range(3):<br>    if i == 99:<br>        break<br>else:<br>    print(&quot;Did not break!&quot;)  # This will print</pre><p>Same can be done with while loop.</p><p>Now some of you geniuses woud say something like this: “Hey we learnt in Python 101 class that you can also use else in try block.”</p><p>While you distinguished geniuses are correct, but that else after the try block is different.</p><p>Here is a quick comparison:</p><ul><li>try ... else is about <strong>exceptions</strong>: the else is skipped if any exception is raised in the try.</li><li>loop ... else is about <strong>flow interruption via </strong><strong>break</strong>: the else is skipped only if break is used.</li></ul><p>Now name that class “Python 102” after adding this into the syllabus.</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Cleaning up after you have made too many temporary variables within a loop</li><li>With it you would not need to update a flag like found=False</li><li>Lock a user account after too many retries</li></ul><h3>Walrus Operator</h3><p>This was popularized a while back with the release of Python 3.8, but not commonly known.</p><p>Walrus operator is a new operator (usable in Python 3.8+) which dynamically assigns value to a variable, while that value is being used somewhere. Yes I know it is kind of confusing:</p><pre>if (n := len(&quot;hello&quot;)) &gt; 3:<br>    print(n)  # 5</pre><p>Here you are essentially assigning the value of len(&#39;hello&#39;) to n, while also using this value is comparison against the literal 3.</p><p>Here is a nerdy face emoji with buck teeth I made using walrus operator</p><p>:=(B)</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Emojis ofc</li><li>Saves you from computing something twice, when you can just access the variable later.</li></ul><h3>Meta Classes</h3><p>Just like classes are used to define how the object is going to behave. similarly Meta classes are used to define how the Classes are going to behave.</p><p>Meta classes are defined within a class. You can say that it is like a class within a class.</p><pre>class MyMeta(type):<br>    def __new__(cls, name, bases, dct):<br>        dct[&#39;magic&#39;] = lambda self: &quot;✨&quot;<br>        return super().__new__(cls, name, bases, dct)<br><br>class MyClass(metaclass=MyMeta):<br>    pass<br><br>print(MyClass().magic())  # ✨</pre><p>Track the sparkle emoji, and see that the magic() function is actually defined in the meta class.</p><p>The reason why I am discussing this here, is because other languages do not commonly use meta classes to modify the class behaviour. They have other mechanisms in place for that.</p><p>Also a worthy note here would be that existence of Meta Classes signify that Python Classes themselves are Objects on a lower level. Mind blown right?</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>You can use it in attribute enforcement. Which basically means that you can enforce certain rules on your class. Like for example, all constants should be named with uppercased name.</li><li>You can create a centralized class registry for managing child classes like plugins.</li><li>Obviously helps in metaprogramming-heavy apps</li><li>You can even build your own declarative ORM. I might show you that but in another blog another time.</li></ul><h3>Using __getattr__ / __getattribute__ to Fake Everything</h3><p>__getattribute__ intercepts all attribute access in a class. In other words, if you want to access any attribute inside a class, you would do MyClass().my_attribute but that would unintentionally call __getattribute__ function to get access to your desired attribute.</p><p>Here is an example where we overwrote the __getattribute__ function to print something before doing whatever it does:</p><pre>class A:<br>    <br>    my_var = 123<br><br>    def __getattribute__(self, name):<br>        print(f&quot;Looking for attribute: {name}&quot;)<br>        return super().__getattribute__(name)</pre><blockquote>📌 Be very careful — don’t call <em>self.__getattribute__(name)</em>, you’ll get a recursion error!</blockquote><p>Note thatmy_var is a class level attribute here, but you can experiment with object level attribute as well.</p><p>Now you can try accessing the my_var in two ways:</p><pre>print( A.my_var ) # this will NOT trigger the custom __getattribute__<br><br>Output:<br>&gt;&gt; 123<br><br>OR<br><br>print( A().my_var ) # this will trigger the custom __getattribute__<br><br>Output:<br>&gt;&gt; Looking for attribute: __getattribute__<br>&gt;&gt; Looking for attribute: my_var<br>&gt;&gt; 123</pre><p>The difference in outputs is because our custom implementation of __getattributes__ is an instance level method.</p><p>So the conclusion you get from this is that, __getattribute__ only runs when the Object is initialized.</p><p>But anyways, on a similar note, you can also use __getattr__ which is slighlty different than __getattribute__ . It only intercepts missing attributes only.</p><pre>class A:<br>    def __getattr__(self, name):<br>        print(f&quot;{name} not found — using fallback&quot;)<br>        return &quot;something else?&quot;</pre><p>❓<strong>Where it can be useful?</strong></p><ul><li>Fallback for alias and attributes</li><li>Lazy loading to defer components until needed</li><li>Audit and access control of every lookups inside a class</li></ul><h3>Dynamic Class Creation</h3><p>Classes are defined using the class keyword. That is how you create a class. But there is another way to create a class and it is super cool.</p><pre>MyDynamicClass = type(&quot;MyDynamicClass&quot;, (), {&quot;x&quot;: 42})<br>print(MyDynamicClass().x)  # 42</pre><p>In the above example I create a class named MyDynamicClass with an attribute called x having the value 42. And I did all of this using the type() built-in function.</p><p>So what’s the deal with this type() function? wasn’t this supposed to be used for checking the datatype of something? Turns out it is dual purpose.</p><p>This is <strong>how Python itself creates classes under the hood.</strong> type() is actually the “metaclass” for all classes.</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Useful for metaprogramming</li><li>Creating classes on the fly (e.g. ORM models, serializers)</li><li>Core to metaclass <strong>mechanics</strong> and tools like <strong>Django</strong>, <strong>SQLAlchemy</strong>, etc.</li></ul><h3>Overloading Operators For DSL-Like Code</h3><p>Firstly, DSL stands for Domain Specific Language, which is nothing but a mini-language tailored to a specific problem domain.</p><p>Operator overloading is like redefining what an operator does. 2+2=4 right? what if you could declare that + sign will from now on yodel instead of adding the two numbers? That is how powerful the operator overloading is.</p><pre>class Num:<br>    def __init__(self, value): self.value = value<br>    def __add__(self, other): return Num(self.value + other.value)<br>    def __repr__(self): return f&quot;Num({self.value})&quot;<br><br>print(Num(5) + Num(3))  # Num(8)<br><br>print(Num(5) - Num(3))  # TypeError: unsupported operand type(s) for -: &#39;Num&#39; and &#39;Num&#39;</pre><p>The __add__ method represents the + operator. Similarly there are other specific methods for each operator in a class instance.</p><p>In the above example we defined the how the + operator works if two Num() objects are added, so we got an expected response. But when we tried to subtract both, it gave us an error saying that we haven’t yet implemented how the - operator would work for two instances of Num() objects.</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Packages like tensorflow, pandas and SQL alchemy use this all the time</li><li>You could also create a new DSL out of existing rules like this</li><li>Simulate Math and Symbolic computations</li><li>Implementing finite state machines</li></ul><h3>Self-Defining Functions</h3><p>Now we are talking about functions that do one thing when called and another when called again.</p><pre>def f():<br>    print(&quot;First time&quot;)<br>    global f<br>    f = lambda: print(&quot;Now I do something else&quot;)<br><br>f()  # First time<br>f()  # Now I do something else</pre><p>Note that I used a global keyword to reference the function definition that is recognized globally.</p><p>❓<strong>Where it can be useful?</strong></p><ul><li>Single time initializations. First call will connect to the database and all other calls will persist the connection state</li><li>It helps in performance optimizations. No need to define extensive checks and conditionals just to make the function behave differently the next time you call it</li><li>You even use it in plugin callback/bootstrapping. Prepare the dynamic code on first function call and then use the stored code on each preceding calls.</li></ul><h3>Final Word</h3><p>You may not use the knowledge I shared with you on a daily basis. But knowing it is definitely putting on a place higher than just every other Python programmer. This could prove to be your value proposition when you make or break a deal. Catch my drift? So the next time someone asks, how flexible are you, you say I’m as flexible as a python, and then proceed to destroy their notion of how Python should work.</p><p>As for how did I discover these flexible uses of Python, well, I just played with the code and looked around to see what was possible. And that is all you need to become a great programmer … curiosity is the the key to transition from “someone” to “distinguished”. Keep learning more and don’t stop.</p><p>The usecases I shared with you were just what I could think of at the moment. If you have any other ideas for any new usecases I did not cover, please comment below.</p><p>I’m open for connection, if you want to chat. You can reach me out through <a href="https://linkedin.com/in/hammad.ai">my Linkedin</a>.</p><p>And don’t forget to show off and flex whenever you can in front of the recruiters. They asked you to own the stage, and that is what you should do.</p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to read your feedbacks and will reply at my earliest.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0b64a88dbfd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How I Mastered SOLID Principles & Became a Starfish]]></title>
            <link>https://medium.com/@dev-in-trenches/how-i-mastered-solid-principles-became-a-starfish-078fa843bf75?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/078fa843bf75</guid>
            <category><![CDATA[intuition]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[oop]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Thu, 06 Feb 2025 21:27:47 GMT</pubDate>
            <atom:updated>2025-02-06T21:27:47.335Z</atom:updated>
            <content:encoded><![CDATA[<h4>Intuitive way to master SOLID Principles in OOP</h4><p>You have tried and may remembered some part of SOLID principles. Maybe you completely forgot and just could not find any intuitive way to memorize this crucial concept. That is exactly why I am writing this article. This is how I did it and now I am sharing the intuition with you.</p><p>I’m not aiming to explain this concept. My main goal is to make this concept so intuitive and human-friendly that it becomes easier to remember and recall during your interviews.</p><h4>TL;DR</h4><p>Yes, there are thousands of articles like this one which talk about the solid principles out there. To be honest, I didn’t find (most of) them particularly useful maybe since they were trying to teach me the concepts, when I didn’t even know OOP quite well at that time. Or maybe the definitions and examples seemed confusing to me.</p><p>In any case, it is going to be a troublesome concept for those who are just starting out in this career path.</p><p>The key is to boil the concepts down to a very dumb simplified version. And no, I am not talking about the one-liner definitions you often see whenever you read about SOLID. Those can be misleading and abstract, since they want to cover a wide range of meanings. Still I found out that they can dumbed down to a very brain-friendly definitions.</p><blockquote>📌 This is my take for how to understand this concept. You are free to accept or reject this notion.</blockquote><p>But for you to better understand SOLID, you must first understand the OOP terminologies. But the thing is everyone on the internet will teach you OOP using a programming language of their own choice. That would make you <em>language focused</em> and before you know it, you will be understanding OOP as well as how the programming language works. What if you coujld learn about it in a <em>context free</em> way, where you would just learn about the OOP concepts and leave the programming language out of the window? Thankfully I have a sponsor which is me, myself and I have just the article for you if you are willing to learn.</p><p><a href="https://medium.com/@hammad.ai/learn-oop-concepts-without-any-language-context-11d56b161f4">Learn OOP Concepts Without any Language Context(Starter Pack)</a></p><p>Sorry about the shameless self promotion. Anyways, time to get down to business.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/868/1*LfboaTxMu-fG71uXee_0gg.png" /></figure><p>Don’t mind the starfish, it is just for show. Just like you, who will be showing off to the recruiters how good is your understanding of SOLID.</p><h3>1- Single Responsibility Principle</h3><p>This one is fairly simple and probably the only one you remember out of the other, more vague principles. It simply means that a single class has only one responsibility. If you want it to perform something out of its <em>assigned</em> responsibility, then you better make another class for it.</p><p>Of course I would also be showing you how it would look like in code. Here is a violation of Single Responsibility Principle:</p><pre>class User {<br>  saveToDatabase() { /* Database logic */ }<br>  sendEmail() { /* Email logic */ }<br>}</pre><p>Here is the same code but with three different classes for three different responsibilities:</p><pre>class User {<br>  // Only user-related data and methods<br>}<br><br>class SomeDatabaseORMClass {<br>  saveToDatabase(user) { /* Database logic */ }<br>}<br><br>class Emails {<br>  sendEmail(user) { /* Email logic */ }<br>}</pre><p>In the solution, we successfully divided the single User class into three different classes each with a <em>single</em> <em>responsibility</em>. User class only handles user related stuff. SomeDatabaseORMClass handles connecting with the database and storing stuff on the database. And finally Emails class only handles connecting to the email server and sending or receiving emails.</p><p>So for the first lesson, we conclude this with:</p><blockquote>Only one responsibility per class</blockquote><h3>2- Open/Closed Principle</h3><p>Open closed principle is just like replying with a “<em>yes and no</em>”, for a question.</p><p>Need an example?</p><p><strong>Jack:</strong> Hey, Jill! what do you think? Is our way of fetching a pail of water from up the hill, efficient and optimized?</p><p><strong>Jill:</strong> <em>Yes and no</em> Jack.</p><p><strong>Jill:</strong> No because, obviously it hurts my legs to run with a bucket full of water.</p><p><strong>Jill:</strong> Yes because it is the most efficient way we can afford right now. We don’t own a donkey or a wheelbarrow remember?</p><p>Now back to the donkey at hand. Open/Closed principle, just like a “yes and no” reply, says something similar.</p><p>The Class is “Open” if we want to <em>extend</em> it’s functionality. But it is “Closed” if we want to modify any code/behaviour of its methods.</p><blockquote>📌 Notice that the word <strong>extend</strong> here, means inheritance in OOP.</blockquote><p>Let’s look at some code now:</p><pre>class Shape {<br>  area() {<br>    throw new GeneralError(&#39;Method not implemented.&#39;);<br>  }<br>}<br><br>class Circle extends Shape {<br>  area() {<br>    return Math.PI * this.radius * this.radius;<br>  }<br>}<br><br>class Square extends Shape {<br>  area() {<br>    return this.side * this.side;<br>  }<br>}</pre><p>This is a very generic example you will find in many places. It features three classes Shape , Circle and Square. Note that all three classes have a method called area(), and both Circle and Square classes inherit from the Shape class.</p><p>If you tried calling area() within the Shape class, you will receive an error, because the method wants to be <strong>overridden </strong>(as in method over-riding).</p><p>Even though the Shape class is made in such a way, that it just wants to make you change that throw new Error() statement. But no no no no no, we don’t do that in Open/Closed Principle. Instead if you want to change it’s behaviour of throwing an error at you, you first inherit that class into another class, override that method, and then call it.</p><p>But if you were to change the area() method inside the Shape class, you might only do something like changing the error type it throws, like right now it is throwing a GeneralError() and you might change it throw a VerySpecificErrorType().</p><p>Note that this Open/Closed principle, encourages using <strong>abstract classes</strong> like Shape and <strong>method overriding</strong>.</p><p>So for Open/Closed Principle we conclude with:</p><blockquote>The existing code works, so don’t mess with it. If you really want to, then extend it and override it.</blockquote><p>This principle encourages you to use abstract classes by inheriting it into your concrete classes.</p><h3>3- Liskov’s Substitution Principle</h3><p>Seriously, out of all the names … this name does not explain anything about what this principle is about other than it somehow references some kind of substitution. Liskov’s name here does not mean anything unless her parents named her scientifically and taught her all about computers and waited years afters years, until she published about the substitution principle … End of my rant.</p><p>Imagine this: while working with OOP, you are eventually going to run into <strong>inheritance</strong>. And you know that one base class can be inherited by many <em>other classes</em>. I’m going to call these <em>other classes</em> as “sub-classes”.</p><p>Now since these sub classes are inheriting from the base class, they should all share whatever functionality was in the base class right? Let’s see some code and then I will ask you some more questions, ready?</p><pre>//This is my base class<br>class Bird {<br>  fly() { print(&#39;Flying&#39;) }<br>}</pre><p>You see here I have a class name Bird which has a single method called fly(). Now imagine that I create a subclass which inherits from this Bird class, and I call the fly() method on the subclass rather than the Bird something like this:</p><pre>//This is my base class<br>class Bird {<br>  fly() { print(&#39;Flying&#39;) }<br>}<br><br>//This is a subclass<br>class Penguin extends Bird {<br>  //this is empty<br>}<br><br>Penguin().fly()</pre><p>What do you think should happen when I call the fly() method on the Penguin class? Just like everyone would expect, it should print “Flying” right?</p><p>This should also be same for <em>any</em> <em>other subclass</em> that inherits from the Bird class. But what if the Penguin class <strong>overrides</strong> the fly() method? What would be the point of writing the fly() logic in the Bird class anyways? This simply breaks the original logic of the fly() method.</p><p>And this is exactly what Mrs. Liskov is trying to tell us. She simply wants to stop us from changing <em>any predefined </em>behaviour from the base class. That is her way of saying that:</p><blockquote>Child classes should behave just like their parents, just because they inherited it.</blockquote><blockquote>📌 By “behave”, I mean methods in a class by the way.</blockquote><p>You should be able to call base class methods through any of its subclasses without observing any change in behaviour.</p><p>But wait, didn’t this just violate the Open/Close Principle? Technically no, because in Open/Close Principle we:</p><ol><li>created an abstract class</li><li>which we inherited into a concrete class</li><li>and override the methods of the abstract class</li></ol><p>In that scenario, the abstract class was meant to be overridden. Meanwhile, here the parent classes are concrete classes.</p><p>And this my friends, is the substitution she was talking about. Basically the subclasses are substituting the base class and are still able to run the same methods that the base class had.</p><p>This principle encourages you to preserve the functionality of your base classes whenever you perform polymorphism or simply inheritance.</p><h3>4- Interface Segregation Principle</h3><p>There are lots of vocabulary you need to understand here. <strong>Interface</strong> refers to the class which is a part of OOP system. It is a class, the only duty of which is to provide a blueprint for another class. The interface, unlike abstract class does not implement any logic, it just contains the names of the methods the other fully implemented class should have.</p><p>Here is some code, so you will understand better:</p><pre>// it only contains the names of the methods<br>interface Worker {<br>  work()<br>  eat()<br>}<br><br>// the class implemented the logic within those methods<br>class Robot implements Worker {<br>  work() { print(&#39;Working&#39;) }<br>  eat() { throw new Error(&#39;Robots don’t eat!&#39;) }<br>}</pre><blockquote>📌 Usually programming languages have a special keyword to define an interface. Just like you see above, interface is defined with the interface keyword, while class is implemented with a class keyword.</blockquote><blockquote>But nonetheless, interface is being inherited just like any other base class would be.</blockquote><p>Before you ask, interface and abstract classes are two different things. Here is a quick comparison:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/891/1*_pjFGtCNXNWiC8f4TUGQUw.png" /></figure><p>Ok enough with the side lesson, lets resume the discussion on the Interface Segregation Principle.</p><p>So you saw my interface and class example in code above. You know how interfaces work and what purpose do they serve. It is time we look into the other vocabulary that was presented to us: Segregation — which only means “<em>separation into parts</em>”.</p><p>In our Worker and Robot example, the Worker interface has two method names i.e. work() and eat(). Now we know that these two methods are completely unrelated to each other.</p><p>If we were to have another method called drink() then we might say that it relates to eat() method because both them symbolize consumption of some sort of food.</p><p>Similarly if we had a method called liftWeights() then we might say that it relates to the work() method.</p><p>But for simplicity, lets keep ourselves from adding more methods into the picture.</p><p>Since both of those methods, eat() and work() are unrelated, it only makes sense to keep them both in separate interfaces like this:</p><pre>interface Workable {<br>  work();<br>}<br><br>interface Eatable {<br>  eat();<br>}<br><br>class Human implements Workable, Eatable {<br>  work() { console.log(&#39;Working&#39;); }<br>  eat() { console.log(&#39;Eating&#39;); }<br>}<br><br>class Robot implements Workable {<br>  work() { console.log(&#39;Working&#39;); }<br>}</pre><p>Just like inheritance you can often extend more than one interface just like I have shown in the Human class.</p><p>What you did here is you separated a single monolithic interface into several parts with respect to their “category”. Of course you, the developer, decides according to which aspect you wish to divide them.</p><p>So we conclude this with:</p><blockquote>Keep your interfaces chunky, not chonky.</blockquote><p>Interfaces should be divided into smaller chunks. Where you group the methods only based on the work they do.</p><p>This principle simply encourages atomicity in your interfaces, which then reflect the same atomicity in your classes. So this is highly compatible with the single responsibility principle.</p><h3>5- Dependency Inversion Principle</h3><p>As we inherit the base classes into the sub classes, we see that the sub classes are now dependent on the base classes.</p><p>Or maybe you wanted to try <strong>composition</strong> in your classes, and you ended up with something like this:</p><pre>class MySQLDatabase {<br>  connect() {<br>    print(&quot;Connecting to MySQL...&quot;);<br>    // MySQL-specific connection code<br>  }<br>}<br><br>class UserService {<br>  constructor() {<br>    this.db = new MySQLDatabase();<br>  }<br>  <br>  getUser() {<br>    this.db.connect();<br>    print(&quot;Fetching user data...&quot;);<br>  }<br>}<br><br>// initialize the user service class<br>const userService = new UserService();<br>// call the database connection method directly within getUser()<br>userService.getUser();</pre><p>The MySQLDatabase class is responsible for connecting to the database.</p><p>UserService is a class which is responsible for the user-related operations.</p><p>Notice that in the constructor of UserService class, we are using the class variable db to store the connection to MySQL by directly calling the class by its name.</p><p>Then in getUser() method, we are using that same db variable and using it to fetch user-related information from the database.</p><p>The problem here is simple, If you decide to change the MySQLDatabase class to something else in the future, you would also need to make changes to UserService class.</p><p>If you haven’t guessed it yet, right now the UserService class is <em>directly</em> <em>dependent</em> on the MySQLDatabase class.</p><blockquote>📌 Notice that I used the word “directly” here which is the opposite of the word this principle tells us to follow … i.e. “inversely” or “inversion”, therefore we call it <em>dependency inversion</em>.</blockquote><p>Instead of having the UserService class rely on MySQLDatabase class, we can introduce some level of abstraction here, like this:</p><pre>// same as before<br>class MySQLDatabase {<br>  connect() {<br>    print(&quot;Connecting to MySQL...&quot;);<br>    // MySQL-specific connection code<br>  }<br>}<br><br>class UserService {<br>  constructor(database) {<br>    this.db = database;  // Database is injected, not hardcoded<br>  }<br>  <br>  // this is also the same as before<br>  getUser() {<br>    this.db.connect();<br>    print(&quot;Fetching user data...&quot;);<br>  }<br>}<br><br><br>const db = new MySQLDatabase(); // You pass this db variable into the constructor as a dependency<br>const userService = new UserService(db);<br>userService.getUser(); // works the same</pre><p>Notice the changes inside the constructor of UserService class. We are not directly assigning the db variable. Now we have successfully <em>abstracted</em> how the UserService class interacts with the database.</p><p>The UserService class does not know what will be passed into the constructor, but it knows at least that whatever is passed into the db variable, will probably have a method called connect().</p><p>This might not look much fancy to you but its true potential can easily be seen below:</p><pre>// same as before<br>class MySQLDatabase {<br>  connect() {<br>    print(&quot;Connecting to MySQL...&quot;);<br>    // MySQL-specific connection code<br>  }<br>}<br><br>class PostgreSQLDatabase {<br>  connect() {<br>    print(&quot;Connecting to PostgreSQL...&quot;);<br>    // PostgreSQL-specific connection code<br>  }<br>}<br><br>class MongoDatabase {<br>  connect() {<br>    print(&quot;Connecting to Mongo...&quot;);<br>    // Mongo-specific connection code<br>  }<br>}<br><br>class UserService {<br>  constructor(database) {<br>    this.db = database;  // Database is injected, not hardcoded<br>  }<br>  <br>  // this is also the same as before<br>  getUser() {<br>    this.db.connect();<br>    print(&quot;Fetching user data...&quot;);<br>  }<br>}<br><br>const db = new MongoDatabase(); // use which ever database class you want<br>const userService = new UserService(db);<br>userService.getUser(); // works the same</pre><p>I simply added PostgreSQLDatabase class and the MongoDatabase class into the picture.</p><p>Now you can easily use any of the database you like and pass it into the UserService class. This class would not mind anything as long as there is a connect() method inside the db variable.</p><p>So we conclude this with:</p><blockquote>Don’t glue classes together directly . Use a plug so you can swap parts easily.</blockquote><p>You will see this pattern being followed in several frameworks like Laravel and Nest.js.</p><h3>With That … Here Are A Few Pointers</h3><p>As in my personal experience, I can tell you this that SOLID principles are not always the right answer. There have been instances where I had to violate maybe two or three principles altogether. In the end, it is all about getting the job done in the most cost-friendly and optimized way.</p><p>But tech interviews tend to make it a really big deal. The reason for that is simple, If you know how to structure your code then you are less likely to fall into pits where it is very difficult to recover from. You might end up stacking a lot of technical debt before you know it.</p><p>Once you get the hang of it, you will know yourself when to forfeit the tradition and follow your path.</p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to read your feedbacks and will reply at my earliest.</p><p>Also, if you want me to write something you’d be interested in, please do let me know. Here is my <a href="https://www.linkedin.com/in/hammadai/">Linkedin</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=078fa843bf75" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Host A Blog Without A Backend]]></title>
            <link>https://medium.com/@dev-in-trenches/host-a-blog-without-a-backend-ce3931c1cc57?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/ce3931c1cc57</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[markdown]]></category>
            <category><![CDATA[blogging]]></category>
            <category><![CDATA[blog]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Sun, 05 Jan 2025 20:05:36 GMT</pubDate>
            <atom:updated>2025-01-07T19:11:13.831Z</atom:updated>
            <content:encoded><![CDATA[<p>Do you have a blog that you want to host but just want to do it for fun or maybe as a hobby just like I do? … without spending anything that is. Maybe this is your motive for clicking on this article or maybe the idea of hosting something without any backend support piques your interests.</p><p>In any case, you will not go empty handed today, since not only I will tell you the concept of how to host your own blog site without any support from backend, but I will also show you two example: one using React.js and another using Vanilla JS for those who like simplicity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CG3NuQ_VD5R1z-QB" /><figcaption>Photo by <a href="https://unsplash.com/@impatrickt?utm_source=medium&amp;utm_medium=referral">Patrick Tomasso</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>My Motive</h3><p>As you know I am a blogger who likes to share my stories as a software engineer and help any individuals with any questions, those who might be looking for some straightforward and insightful answers.</p><p>After I made my portfolio site, I made a section in there where I am listing all of my blogs. Each of those blogs are linked to medium.com articles, so when people click on any blog in my portfolio site they get redirected here to read the article. Naturally I started looking for alternatives to host my own blog.</p><p>As a software engineer I could always make one from scratch with full control over every aspect of the blogging solution, but I could also use the same time working on something more interesting which I can <em>write</em> and <em>share</em> about.</p><p>Now just to be clear, I am not opposed to the idea of spending on hosting providers. In fact, I would not think twice before spending money on something which can return the investment at some point in the future.</p><p>Anyways, the first alternative that came to my mind was <a href="https://wordpress.org">Wordpress</a> but it required me to own and host a webserver, which consequently meant me spending $$$. None of my blogs here on medium are “members-only” because it is my hobby and spending on a hobby which I don’t earn anything from seemed like a no-no to me. I could use Google ads to generate revenue but that would only clutter things up and drive people away right? … right?</p><p>In other words, I do not like when I see Ads popping up in the corners. So I would naturally assume that my readers do not like it either.</p><p>While I do know <em>why</em> you might have clicked on this article, I want to make it clear that the title up there is in fact, a bit <em>misleading</em>.</p><p>I said that I will not use backend, but I am using one hosted by someone else, although it is completely free to use. To cut to the chase, I am using Github as a <em>hosting service</em> for my blogs and I created a frontend in <a href="https://react.dev">React.js</a> (you could use any other frontend framework you like) deployed on <a href="https://vercel.com">Vercel</a>, to show the content taken from Github with my custom CSS styles.</p><p>Of course you will have the complete liberty of choosing how your blog presents itself to your visitors.</p><h3>Before anything else</h3><p>There are a couple of things I want to make clear before you continue reading.</p><p>A typical blogging application consists of a backend which stores and provides each blog content individually. Typically there is a listing page in the frontend, where all of the blogs are listed and when the user clicks on any one of the links, they are redirected to a page where all of the content of that blog (including images, gifs, embeddable elements etc) will be shown.</p><p>And when the admin changes some words on any one of the articles, that change would get reflected on the user’s side almost immediately.</p><p>This is the flow I was targeting to use in my own blogging solution.</p><p>And before you ask … Yes, it does require some extra work but it is still somewhat easy to manage (as far as I think), and also yes, there are some limitations which we will discuss later in this article. But enough jibber-jabber, let’s see how I did it.</p><h3>Use Github to host your blog content</h3><p>This is fairly simple, as you only need to make a repository and upload some files to it. In my case I uploaded some markdown files.</p><p>Each of those markdown files will act as a single blog article, and the content inside it will be written in the markdown syntax. Just to show an example, here is a sample markdown file and its content:</p><pre># My Blog Title<br><br>Some intro explaining what this article is about like I always do <br>when I write one.<br><br>![title_image](link/to/title_image.jpg)<br><br>Some more content which explains the topic in detail.<br><br>## Sub heading 1<br><br>sub heading content 1<br><br>&gt; some famous quote from someone important<br><br>## Sub heading 2<br><br>sub heading content 2<br><br>| item 1 | item 2 |<br>|--------|--------|<br>|comparision 0-1|comparision 1-1|<br>|comparision 0-2|comparision 1-2|<br><br># Footer<br><br>footer content</pre><p>As you can see the markdown contains most of what will be present in a typical markdown file. That is it, till here. The real shenanigans is in the frontend, and it is prime time we start discussing that.</p><h3>Create a frontend</h3><p>For a frontend, you can think of two kinds of pages to show to the visitor:</p><ul><li>The <strong>listing page</strong> where all of your blogs are listed. Let us call it Index.jsx</li><li>The <strong>blog page</strong> itself which shows the blog content with any images, tables and embeddable elements. Let us call it Blog.jsx</li></ul><blockquote>📌 I used React.js in my case but you can use anything else you like (even Vanilla JavaScript can work). But I will be explaining in terms of React.js to keep things consistent.</blockquote><p>The Blog.jsx page will be created as a component which will look like this:</p><pre>import React, { useState, useEffect } from &quot;react&quot;;<br><br>function Blog(props) {<br>  const { blogContentLink } = props;<br>  const [htmlContent, setHtmlContent] = useState(&quot;&quot;); // State to store the HTML content<br>  <br>  useEffect(() =&gt; {<br>    const fetchMarkdown = async () =&gt; {<br>      // TODO: write some logic here to fetch and convert markdown content to json<br>    };<br>    if (blogContentLink) {<br>      fetchMarkdown();<br>    }<br>  }, [blogContentLink]);<br>  return (<br>    &lt;div&gt;<br>      &lt;div<br>        dangerouslySetInnerHTML={{ __html: htmlContent }} // Render the HTML content<br>      /&gt;<br>    &lt;/div&gt;<br>  );<br>}<br>export default Blog;</pre><p>Notice that I have a TODO comment in there. This is where we will be writing our markdown to HTML conversion logic.</p><p>Don’t worry about the dangerouslySetInnerHTML attribute. This is usually not recommended when you have a server, but in our case, we do not have a server.</p><p>Also notice that I am sending blogContentLink as a prop to this component.</p><p>This blogContentLink is the <a href="https://github.com/orgs/community/discussions/44370">Github Raw URL</a> which will respond with a 200 HTTP code and the markdown content of a file. Of course the markdown content needs to be converted into HTML to be able to get rendered in the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">DOM</a>.</p><blockquote>📌 In case you do not know, Raw Github URLs are special URLs which serve raw contents of a file. These URLs start like this:</blockquote><blockquote><a href="https://raw.githubusercontent.com">https://raw.githubusercontent.com</a></blockquote><p>But remember that our content was written in markdown right? Therefore, we need a way to convert the markdown into HTML. Luckily there happens to be a popular quote among JavaScript Developers:</p><blockquote>“There is a JavaScript Library for that too“</blockquote><blockquote>— told by various JS Devs around the globe</blockquote><p>Which brings us to our next step …</p><h3>Convert Markdown into HTML</h3><p>For this I am using <a href="https://showdownjs.com">showdown.js</a> which is a bidirectional converter between markdown and HTML.</p><p>This library is very simple to use. Below is an example with vanilla JS:</p><pre>const markdownRawUrl = &quot;https://raw.githubusercontent.com/Blankscreen-exe/host-a-blog-without-a-backend/refs/heads/main/README.md&quot;;<br><br>fetch(markdownRawUrl)<br>.then( data =&gt; {<br>  let md_content = data.text();<br>  let converter = new showdown.Converter(); // initializing showdown.js object<br>  let html_content = converter.makeHtml(md_content); // convert markdown into HTML<br>})<br>.error( <br>  error =&gt; console.error(&#39;Error fetching the Markdown file:&#39;, error) <br>);</pre><p>The example above is in Vanilla JavaScript just to show you how it works. We will be using the same code in our React.js component.</p><p>Of course there are alternatives to showdown.js which may or may not work better than this one. I felt happy using showdown.js. You should also pick the alternative which makes you happy.</p><p>Now we have the pieces of the puzzle, so how do they all fit together?</p><h3>Combining everything we have learned so far</h3><p>You will have your blogs (written in markdown) in your repository arranged like this:</p><pre>blogs/<br>|- my_blog_title_1.md<br>|- my_blog_title_2.md<br>|- my_blog_title_3.md<br>|- my_blog_title_4.md<br><br>data/<br>|- blogList.json<br><br>components/<br>|- Blog.jsx<br>|- Index.jsx<br><br>App.jsx<br><br>... other react components</pre><p>You will then create a .json file to hold the listing details of each blog. Let us call this file blogList.json. This file will be stored anywhere in the project where it can be accessed by the Index.jsx component. The sample blogList.json looks like this:</p><pre>// inside data.json<br><br>[<br>  {<br>    &quot;blogFileName&quot;: &quot;my_blog_title_1.md&quot;,<br>    &quot;blogTitle&quot; : &quot;My Blog Title 1&quot;<br>  },<br>  {<br>    &quot;blogFileName&quot;: &quot;my_blog_title_2.md&quot;,<br>    &quot;blogTitle&quot; : &quot;My Blog Title 2&quot;<br>  },<br>  {<br>    &quot;blogFileName&quot;: &quot;my_blog_title_3.md&quot;,<br>    &quot;blogTitle&quot; : &quot;My Blog Title 3&quot;<br>  },<br>  {<br>    &quot;blogFileName&quot;: &quot;my_blog_title_4.md&quot;,<br>    &quot;blogTitle&quot; : &quot;My Blog Title 4&quot;<br>  }<br>]</pre><p>Now you just need to loop over this JSON array and and show it in the listing page which we decided that we will call Index.jsx. Of course each listing item will provide the Blog.jsx component with a URL prop blogContentLink which would be a Raw Github URL pointing to any one of the markdown file.</p><p>Make sure that the blogFileName value matches the file name stored inside blogs/ folder.</p><p>For reference, your listing page should look something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/1*puxlYFODe8iSsuKwvS0C_w.png" /><figcaption>example view of listing page</figcaption></figure><p>With this we are finally ready to finish the Blog.jsx file we left back there. Here is the update code:</p><pre>import React, { useState, useEffect } from &quot;react&quot;;<br>import showdown from &quot;showdown&quot;;<br><br>function Blog(props) {<br>  const { url } = props;<br>  const [htmlContent, setHtmlContent] = useState(&quot;&quot;); // State to store the HTML content<br>  <br>  const converter = new showdown.Converter({tables: true}); // Initialize the showdown converter<br>  useEffect(() =&gt; {<br>    const fetchMarkdown = async () =&gt; {<br>      try {<br>        const response = await fetch(url); // Fetch markdown content from the URL<br>        if (!response.ok) {<br>          throw new Error(`Error fetching markdown: ${response.statusText}`);<br>        }<br>        const markdown = await response.text();<br>        const html = converter.makeHtml(markdown); // Convert markdown to HTML<br>        setHtmlContent(html);<br>      } catch (error) {<br>        console.error(&quot;Error fetching or converting markdown:&quot;, error);<br>      }<br>    };<br>    if (url) {<br>      fetchMarkdown();<br>    }<br>  }, [url, converter]);<br>  return (<br>    &lt;div&gt;<br>      &lt;div<br>        dangerouslySetInnerHTML={{ __html: htmlContent }} // Render the HTML content<br>      /&gt;<br>    &lt;/div&gt;<br>  );<br>}<br>export default Blog;</pre><p>That’s about it actually. Now your Blog.jsx component is able to render markdown formatted text. And now you can update the markdown file in the repository, and those changes will be reflected on your blog site.</p><p>With my custom CSS styles, my version of the blog page looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5gUza65A8URoBU8b4lFRzw.png" /></figure><p>As I said, I prepared two types of demo for this blog. One is made with React.js and other one is made using Vanilla JavaScript.</p><p>In my source code, the vanilla JS version is in the root directory of the repository. Whereas the React.js implementation is located inside the react-sample-project folder:</p><p><a href="https://github.com/Blankscreen-exe/host-a-blog-without-a-backend">GitHub - Blankscreen-exe/host-a-blog-without-a-backend: converting markdown from github raw content into renderable HTML</a></p><p>You can visit the live Vanilla JS demo Here:</p><p><a href="https://blankscreen-exe.github.io/host-a-blog-without-a-backend/">Host A Blog Without Backend</a></p><p>The demo above will enable you to feed in any Github Raw URL of a markdown file and see its HTML being rendered inside a &lt;div&gt; element.</p><p>While the React.js Live Demo is not available, you can still run the project yourself if you like. I have included the instructions how to run the app in the README.md.</p><h3>Limitations</h3><p>As far as limitations are concerned using this method to host your own blog website, we can see that most of the limitations are bound to not having an actual backend system.</p><p>If your requirements for your blogging platform includes any features other than hosting and serving your blog content, then you are well off using Wordpress or other alternatives.</p><p>Github is only allowing you to serve your blog content and update it whenever you want without making any changes to your client side application. You need to understand that this is the <em>extent</em> of what you are going to get from Github.</p><p>For example, you will NOT be able to do the following:</p><ul><li>Integrate user analytics</li><li>User profiling</li><li>Keeping a track of likes and comments on your blogs</li><li>You get the point, right?</li></ul><p>That is what I feel, is the only major limitation which I should discuss before seeing you off.</p><p>However, if you think that there is another limitation which I did not discuss, then please, by all means, comment below and let me know.</p><h3>Final Word</h3><p>Now you know how you can host your own blog application without the need for any backend. You also know what limitations you would face when using something like this.</p><p>Of course it would not be much of a pain to set something like this up for a hobby blog.</p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to read your feedbacks and will reply at my earliest.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ce3931c1cc57" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why Does Python Allow “print = 123”?]]></title>
            <link>https://medium.com/@dev-in-trenches/why-does-python-allow-print-123-c960c1035209?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/c960c1035209</guid>
            <category><![CDATA[programming-languages]]></category>
            <category><![CDATA[design-philosophy]]></category>
            <category><![CDATA[python-programming]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Tue, 03 Dec 2024 19:32:22 GMT</pubDate>
            <atom:updated>2024-12-03T19:32:22.099Z</atom:updated>
            <content:encoded><![CDATA[<h4>Diving into Python’s design philosophy</h4><p>Not many people know this, but this is a good piece of knowledge to have if you want to show off your understanding in Python Programming Language.</p><p>If you ever try to run print=123, the interpreter would just run it without causing a fuss, although it would seem that it <em>should </em>raise a warning at least if not an exception. The next time you run your print function like you usually do, the interpreter will tell you that an Integer Literal (since we assigned an integer to print) is not a callable i.e. a function.</p><p>What is more fun is that you can do this to almost anything in Python, not just the print() function.</p><blockquote><em>📌</em> There is much to learn about Python’s design philosophy in this article and I have worked for it to be a fun read for the experienced as well as newbies. I hope you will learn about a lot in here and also upgrade your arsenal to impress recruiters too cuz why not?</blockquote><p>If you are a language architecture nerd, you might have guessed, to answer this question we need to dive into the design philosophy.</p><p>But before all that, let’s unpack what we will discuss in this article:</p><ul><li>Everything is an object — a Python’s data model philosophy</li><li>Namespace management and scoping</li><li>Dynamic typing and flexibility</li><li>Trusting the programmers — We are all consenting adults here</li></ul><p>Apart from the above topics, I will also tell you about:</p><ul><li>The tradeoffs</li><li>And how to revert back if you accidentally do run “print=123&quot;</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*YQ8tWD1gGiabXuHCG47lBA.png" /></figure><h3>Everything is an object</h3><p>Most sources and instructors do not go much into this or straight away skip it, although this concept is crucial if you want to <em>engineer </em>applications with Python, not just build it.</p><p>Anyways, let’s study a passage from the <a href="https://docs.python.org/3/reference/datamodel.html">Python Reference Guide — Data Models</a>:</p><blockquote><em>Objects</em> are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects. (In a sense, and in conformance to Von Neumann’s model of a “stored program computer”, code is also represented by objects.)</blockquote><p>This clearly states that everything you see in your Python code is an object. Even the literals including integers, string, lists and of course functions and variables.</p><p>But wait a minute, if you are coming from languages like JAVA and C, you can usually picture functions being <strong>methods </strong>of an object and variables being <strong>attributes </strong>of an object. But how are literals like integers, float and string fit into the picture?</p><p>These literals fit into Python’s <strong>“everything is an object”</strong> paradigm because they are instances of <em>built-in classes</em>. In Python, even simple literals such as 42 or &quot;hello&quot; are objects with attributes and methods.</p><p>Remember, you can call .capitalize() on a string? But now you must be thinking that you cannot call any methods on an integer. If you tried doing this, you will get an error:</p><pre>&gt;&gt;&gt; 123.bit_length()<br><br>SyntaxError: invalid decimal literal</pre><p>This is because the interpreter is assuming that after the decimal point . there would be more numbers to make a floating point number but it finds <em>letters </em>instead. This is something the interpreter is designed to do.</p><p>To properly do this, you need the parentheses(), which is the same thing as what we did before, but this explicitly tells the interpreter what we are trying to do:</p><pre>&gt;&gt;&gt; (123).bit_length()<br><br>7<br><br>&gt;&gt;&gt; int(123).bit_length() # It also works with the int() function too<br><br>7</pre><h4>Is Reassignment Also Valid For Literals?</h4><p>This explanation about the “Everything is an Object” philosophy, will raise yet another question if you are genuinely curious:</p><p><em>If literals are objects too, then can we reassign literals?</em></p><p>Well if you have tried it, it would have given you an error saying something like this:</p><pre>&gt;&gt;&gt; &quot;some string&quot; = 123<br><br>  File &quot;&lt;stdin&gt;&quot;, line 1<br>    &quot;some string&quot; = 123<br>    ^^^^^^^^^^^^^<br>SyntaxError: cannot assign to literal here. Maybe you meant &#39;==&#39; instead of &#39;=&#39;?</pre><p>It clearly says that the interpreter is designed to restrict the reassignment of literals. So what is this hypocrisy?</p><p>To answer this you need to understand the difference between <em>data</em> and their <em>labels</em>.</p><p>Literals, such as 123, &#39;hello&#39;, or 3.14, are <strong>direct representations of data</strong> and are not labels (variable names). When you use a literal in your code, Python directly interprets it as a value, not as a name to which a value is assigned. For example:</p><pre>some_variable = 123  # &#39;some_variable&#39; is a name bound to the integer object 123</pre><p>You can reassign some_variable, but not 123 itself because 123 is not a name. This behavior is crucial to Python because it allows it to use the data behind literals to perform calculations and logical operations.</p><p>In this regard, functions, whether built-in or not, are <em>labels</em> which point to an <em>object</em>.</p><p>Python, by design restricts some data types by making them immutable (<em>emphasis on “some”</em>). But will we be able to reassign those data types if the immutability restriction was lifted? Still the answer is NO. Because don’t forget that these literals are interpreted as data not labels.</p><blockquote><em>📌</em> I understand that this little hypocrisy might be a little confusing to understand. How can an “object” be a “data” and unlike objects, they cannot be reassigned?</blockquote><blockquote>Therefore I am offering a little more clarity on this in the few paragraphs below. You need to blow the minds of the recruiter with this don’t you?</blockquote><h4>What Exactly Are Literals in Python?</h4><p>Literals in Python (e.g., 123, &#39;hello&#39;, 3.14) are <strong>syntactic constructs</strong> in the source code that directly represent objects. When Python encounters a literal in your code, it creates or references the corresponding object in memory during the program&#39;s execution.</p><h4>Do Literals Exist As Objects Before Execution?</h4><p>No, <a href="https://docs.python.org/3/library/stdtypes.html">literals do not exist as objects before the program starts</a>. Instead:</p><ul><li>Python’s <strong>parser</strong> reads the source code.</li><li>It identifies literals (like 123 or &#39;hello&#39;) and their corresponding types.</li><li>During execution, Python <strong>creates</strong> or <strong>reuses existing objects</strong> for these literals as needed.</li></ul><p>For example:</p><pre>x = 123  # Python creates an integer object 123 and binds it to &#39;x&#39;<br><br>y = 123  # Python reuses the same integer object 123 (for small integers)</pre><p>Python doesn’t initialize “all possible literals” before a program starts — it processes them dynamically during runtime.</p><h4>How Literals Represent Data, Not Classes</h4><p>When you write a literal like 123 in your code, Python implicitly:</p><ul><li>Associates it with a specific type (class):</li></ul><pre>123 --&gt; int<br><br>&#39;hello&#39; --&gt; str<br><br>3.14 --&gt; float</pre><ul><li>Creates an instance of that type (class) to represent the literal.</li></ul><p>For example:</p><pre>x = 123  # An instance of &#39;int&#39; is created<br><br>y = &quot;hello&quot;  # An instance of &#39;str&#39; is created<br><br>z = 456 # An BRAND NEW instance of &#39;int&#39; is created</pre><p>At runtime, literals represent <strong>instances of specific classes</strong>, not the classes themselves. They no longer behave like labels for those classes.</p><p>If you still cannot understand words, let the code do the talking:</p><pre>class MockInteger:<br>    def __init__(self, value):<br>        self.value = value<br>    <br>    def __repr__(self):<br>        return f&quot;{self.value}&quot;  # Represents the data directly<br>    <br>    def __add__(self, other):<br>        if isinstance(other, MockInteger):<br>            return MockInteger(self.value + other.value)<br>        return MockInteger(self.value + other)<br><br># Creating literal-like objects<br>num1 = MockInteger(123)<br>num2 = MockInteger(456)<br><br>print(num1)  # Output: 123<br>print(num1 + num2)  # Output: 579<br>print(num1 + 100)  # Output: 223</pre><p>In the above code I have implemented a mock version of the Int() class, which represents the integer data directly and does not point to the class itself. This is done by manipulating the __repr__() method which stands for “Represent”.</p><h4>The Role of Immutability</h4><p>For immutable types (like int or str), Python ensures that the literal represents a fixed object in memory. Even if literals were mutable, Python&#39;s syntax design would still prevent reassigning them because literals represent data directly, not variable names.</p><p>Example:</p><pre>&gt;&gt;&gt; 123 = &quot;hello&quot;  <br><br>SyntaxError: Python does not allow literals to act as variable names</pre><h4>How Python Manages Literals Behind the Scenes</h4><ul><li><strong>For Small Integers</strong>: Python pre-caches small integer literals (e.g., -5 to 256) to optimize memory usage and performance:</li></ul><pre>a = 123 <br><br>b = 123 <br><br>print(a is b)  # True: Both refer to the same pre-cached object</pre><ul><li><strong>For Strings</strong>: String literals may be <strong>interned</strong> (reused) for optimization:</li></ul><pre>x = &quot;hello&quot; <br><br>y = &quot;hello&quot; <br><br>print(x is y)  # True: Both may or may not point to the same object</pre><ul><li><strong>For Larger or Complex Objects</strong>: Python creates new objects as needed.</li></ul><p>Since we are talking about it, lets try and break what I said about the string literals that they may or may not point to the same object:</p><pre># string saying hello<br>x = &quot;hello&quot;<br><br># Creates a string from bytes. <br># It still represents the string &quot;hello&quot;<br>y = b&quot;hello&quot;.decode(&quot;utf-8&quot;)<br><br>print(x == y)  # True: Values match<br><br>print(x is y)  # False: Different objects</pre><blockquote><em>📌</em> There are more ways to break this but I have already deviated from the main topic too much in order to give you more clarity. I am up for further discussions if you like though 😄</blockquote><h4>But What Is This “Stored Program Computer” They Speak Of?</h4><p>In case you are wondering, Von Neumann’s model of a “stored program computer” refers to a type of computer architecture where both instructions (code) and data are stored in the same memory.</p><p>This just means that both the code, and the data for the code, are stored somewhere in the hard-drive, and you can run it anytime by reading from the source. As you might have guessed, this is common in most programming languages we use today, so there is nothing fancy in there.</p><p>Unsurprisingly, Python’s implementation and runtime model are influenced by the stored program concept because:</p><ul><li>Both program code and data are treated as objects.</li><li>This enables advanced features like meta-programming, introspection, and dynamic execution.</li></ul><p>Alright! we get the “everything is an object” part. What now? How does this relate to the elephant in the room?</p><p><em>If you can assign values to variables, and variables are objects, then by logic you can use the assignment operator </em><em>= with objects as well.</em></p><p>Here is some practical evidence for the “everything is an object” philosophy:</p><pre>print(type(123))         # &lt;class &#39;int&#39;&gt;<br>print(type(&quot;hello&quot;))     # &lt;class &#39;str&#39;&gt;<br>print(type(print))       # &lt;class &#39;builtin_function_or_method&#39;&gt;</pre><p>You can see that all of these come from a <em>class</em> one way or another.</p><p>Let me just put the pixels together for the big picture first, and you will get a clearer idea.</p><h3>Namespace Management And Scoping</h3><p>Namespacing refers to the system by which names (identifiers like variables, functions, classes, etc.) are organized and managed in different scopes to avoid conflicts. A namespace is essentially a container (or mapping) that holds a collection of name-to-object bindings.</p><p>Before we discuss namespacing in Python, let&#39;s talk about how the Python’s runtime memory holds information for your code. Then we will move back to discussing the namespaces.</p><p>In the same <a href="https://docs.python.org/3/reference/datamodel.html">Python Reference Guide — Data Models</a> the second paragraph says this:</p><blockquote>Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. The <a href="https://docs.python.org/3/reference/expressions.html#is">is</a> operator compares the identity of two objects; the <a href="https://docs.python.org/3/library/functions.html#id">id()</a> function returns an integer representing its identity.</blockquote><p>We can understand two things from this:</p><ol><li>Python reference guide is written in plain English and it is not that difficult to understand (for those who run away from reading)</li><li>Objects (or everything you see in your Python code) are stored at a specific location/address in memory.</li></ol><blockquote>I may be implicitly encouraging you to look into the Python reference guide.</blockquote><p>With this in mind, let&#39;s try a little experiment:</p><pre>&gt;&gt;&gt; id(print) # The original print function<br>2975807137456<br><br>&gt;&gt;&gt; print = 123<br><br>&gt;&gt;&gt; id(print) # The modified print keyword<br>140732125882616</pre><p>The id() function returns two distinct identities for the original and the modified version of the print function. This means that this new “print” value is being stored at a different location separate from the original built-in print function.</p><blockquote><em>📌</em> For clarity, lets call the original print function the “global definition of print function” and the print after we assign 123 to it as “local definition of print”</blockquote><p>This also means that the global definition of print function is still there, waiting to be called. But the problem arises when you try to call it, and it fetches the local version of print function instead.</p><p>This is known as <strong>shadowing</strong> in Python, and you can learn more about this behavior from <a href="https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value">Python Docs, Section: Core Language</a>. And this characteristic is consistent with the <a href="https://peps.python.org/pep-0020/">Zen of Python’s</a> second line:</p><blockquote>Explicit is better than implicit</blockquote><p>Let&#39;s get back to namespaces.</p><p>You may think of namespacing as a <a href="https://docs.python.org/3/tutorial/datastructures.html#dictionaries">Python dictionary</a> or, if you like, a <a href="https://en.wikipedia.org/wiki/Hash_table">hash table</a>. For every <em>value</em> in the dictionary, there is a <em>key</em> through which you can access it.</p><p>And like a dictionary, there cannot be two keys with the same name. This explains why and how the original print function was shadowed by the new print value.</p><p>To understand why this happens, the LEGB rule can provide a more clearer explanation. And no, this is not about the rainbow.</p><h4>The LEGB Rule: Resolution Order of Namespaces</h4><p>When Python encounters a name, it looks for it in the following order:</p><ol><li><strong>Local</strong>: Names in the current local scope.</li><li><strong>Enclosing</strong>: Names in the enclosing (nonlocal) scopes of nested functions.</li><li><strong>Global</strong>: Names in the global scope of the current module.</li><li><strong>Built-in</strong>: Names in the built-in namespace.</li></ol><p>Since the global definition of print is the last location it will look into, therefore it will always end up with the local definition of print.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/663/1*SNyR1-ivIwzeEOu7r5AOWw.png" /></figure><p>Since you are not reassigning print directly in a Python script, it will reside in the global namespace consequently shadowing the built-in namespace.</p><h3>Dynamic Typing And Flexibility</h3><p>Unlike languages like C and JAVA, Python supports <a href="https://www.techtarget.com/searchapparchitecture/tip/Static-vs-dynamic-typing-The-details-and-differences">dynamic typing</a>. This means that a variable can be of any datatype at any given point in a program execution lifecycle.</p><p>A single variable can hold an <em>integer </em>at one point and a <em>string </em>at another point and a <em>list </em>at another point. Python allows this on-the-fly reassignment of variables and functions. Yes you heard it. Functions are no exception.</p><p>Now if we assume that if Python’s design was to restrict reassignment for specific names (like built-ins), that would break this uniformity and reduce the language’s flexibility.</p><p>But if you have been experimenting all along, you will find out that the for keyword does not support reassignment.</p><pre>&gt;&gt;&gt; for = 123<br>  File &quot;&lt;stdin&gt;&quot;, line 1<br>    for = 123<br>        ^<br>SyntaxError: invalid syntax</pre><p>This, as we discussed before, is the interpreter trying to do its job, which in this case is to find an “iterable” after the for keyword. Which consequently, it does not find and therefore raises an exception.</p><p>So will this work if we somehow bypass the exception? The answer is NO … because these reserved keywords like if, ⁣in, for etc are NOT objects. They are a part of the syntax, and they themselves hold no value.</p><p>Reasons why keyword are not objects:</p><ul><li>Keywords are reserved by the Python language to define its grammar and rules. They represent syntactic constructs, not runtime entities</li><li>These keywords are not bound by any objects and can be used freely</li><li>These keywords serve a predefined, specific role in the language</li></ul><p>Although you cannot directly treat keywords like objects, you can still check or list them using the keyword module:</p><pre>import keyword<br><br># Check if a string is a keyword<br>print(keyword.iskeyword(&quot;for&quot;))  # True<br>print(keyword.iskeyword(&quot;print&quot;))  # False<br><br># List all Python keywords<br>print(keyword.kwlist)</pre><h3>Trusting the programmers</h3><p>I have already answered the technicalities behind the “Why”. But let’s talk about the “Why” as in, why did the Python creators leave this flaw open?</p><p>If you are from the Python community, you would be familiar with this quote (or something similar to this):</p><blockquote>We are all consenting adults here…</blockquote><p>This quote is not part of the official Python documentation but originates from the <a href="https://www.python.org/community/">Python Community</a>, particularly in discussions on forums, mailing lists, and Python Enhancement Proposals (PEPs). It embodies the principle that Python developers are responsible for their actions and are trusted to use features wisely.</p><p>The phrase is often used in discussions about:</p><ol><li><strong>Private Attributes</strong>: Python uses a convention (prefixing an attribute with _ or __) rather than access modifiers like private or protected in other languages. This allows access but signals that it’s intended for internal use.</li></ol><pre>class Example:<br>    def __init__(self):<br>        self._private = &quot;Not really private&quot;<br><br>obj = Example()<br>print(obj._private)  # Allowed, but discouraged</pre><ol><li><strong>Dynamic Typing</strong>: Python does not enforce strict type checking, trusting developers to ensure correct usage of variables and objects.</li><li><strong>Duck Typing</strong>: Python emphasizes behavior over strict type definitions, allowing developers to decide how to use objects.</li></ol><p>Just to save you some time, if you wish to find this quote out in the wild … you can check out <a href="https://mail.python.org/pipermail/tutor/2003-October/025932.html">this mail in the Python mailing list</a>.</p><p>Turns out, this is not a bug, it is a feature 😺</p><h3>Trade Offs</h3><p>There is one obvious trade off here. If you do indeed “accidentally” do something like print=123, it is going to cause errors if you plan to use print in the rest of the script. But it was your own responsibility in the first place so you cannot complain now can you? … can you?</p><p>Me being me, I can think of some awesome uses for this:</p><ul><li>We can use it in <strong>code obfuscation</strong>. Loosely typed languages already gives an edge to obfuscation but with this ability, Python can take it to yet another level</li><li><strong>Customize</strong> your script by rewriting your own interpretations of the built-in functions. I was always a fan of customizations, so I love this behavior</li><li>Mix this ability with <strong>dynamic code execution</strong> and you will unlock even more potential in code obfuscation, customizations and whatever your imagination can take you to</li><li>I am a software engineer and sometimes I have to <strong>test other people’s code</strong> to see if it works or to debug it and fix it. Using this ability I can make unit testing a lot more easier with temporary reassignments of built-in keywords and functions</li><li>Since we are talking about breaking the code (even though temporarily), we could also use this in <strong>cyber security and ethical hacking</strong>. I don’t know much about this field but I sure do know how can I break my own code to get some info from the database if I was hacking into it (I might write about it in another article)</li></ul><p>I honestly don’t know what else is there, but highly believe there are more possibilities with this bug … err, I mean feature. Do me a favor, let me know what else can you think of in the comments 👇.</p><p>Obviously I would avoid doing something like this in production level code, because that code should be something anyone can read and understand. With print=123 I would only be making a code spaghetti which no one asked for.</p><p>You thought I would talk about trade-offs here, but it was all about me being a mad scientist Muahahaha!</p><h3>How Do We Turn It Back?</h3><p>Yes, indeed it is a grave matter at hand. We have disturbed the undisturbed. We have caused chaos among the most serene of gardens. How do we repent and for our sins and undo the imbalance we committed?</p><p>No sweat really. Just do this:</p><pre>del print</pre><p>This will delete the local definition of print() and will no longer shadow the built-in definition.</p><h3>Final Word</h3><p>You have the knowledge, you have the skills. To become a master of the things you do on a daily basis, you just need to be <em>curious</em>. This curiosity is what guided me to explore this behavior in the Python language.</p><p>Who knows what other flaws … I mean undocumented features Python has. You can do it just like I did and maybe write about it too. Just remember to ping me to read it. You can reach me out through <a href="https://linkedin.com/in/hammad.ai">my Linkedin</a>.</p><p>And don’t forget to show off and flex whenever you can in front of the recruiters. They asked you to own the stage, and that is what you should do.</p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to read your feedbacks and will reply at my earliest.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c960c1035209" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advice For When You Get Started As A Junior Developer]]></title>
            <link>https://medium.com/@dev-in-trenches/when-you-get-started-as-a-junior-developer-d2c65057b4bf?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/d2c65057b4bf</guid>
            <category><![CDATA[careers]]></category>
            <category><![CDATA[career-advice]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[advice]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Sun, 01 Sep 2024 19:24:41 GMT</pubDate>
            <atom:updated>2026-02-17T14:29:11.297Z</atom:updated>
            <content:encoded><![CDATA[<h4>Things to do for maximizing the start of your potential career and make the most out of it</h4><p>I will be sharing stories about what I did (or at least wished that I should have done) when I first got hired as a junior developer. There were some things that I was right about and some which I didn’t think of much but proved to be very beneficial in the long run.</p><p>These are the compilation of my best practices at the very start of my career.</p><h3>tl;dr</h3><p>Soft skills is to programmer as algorithm is to a program. Just like a good algorithm makes a good program, good soft skills makes a good programmer. What happens if a programmer doesn’t have any soft skills? you ask … they are similar to a cog in a clockwork where the cog doesn’t change jobs or it’s position and just stays there for as long as <em>necessary</em>. The worst part is … the cog doesn’t decide the end of it’s <em>externally imposed</em> fate. I hope this analogy makes sense.</p><p>This article isn’t my rant about the importance of soft skills. People have done that before. What I’m doing here is showing you a practical approach to make those soft skills beneficial for you in early or further stages of your career.</p><p>Communication, time management, team work, negotiation, problem solving, critical thinking etc all are tools that can be used to maximize your potential, but it is rarely being talked about “how exactly?”. Let’s explore the possibilities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5Z9CifeMjlxj7f0X" /><figcaption>Photo by <a href="https://unsplash.com/@bostonpubliclibrary?utm_source=medium&amp;utm_medium=referral">Boston Public Library</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Humans, as an individual, have improvised and survived throughout the centuries because of these so-called soft skills. But what is the meaning behind this seemingly abstract term. These are the skills that enable you to do human things like feeling empathy, communicating thoughts, taking the lead, solving problems etc.</p><p>Know this, that soft skills are not something that can be taught. As far as I have experienced. These skills are developed as you use them. Doesn’t make sense? It will in a few moments.</p><p>Ask yourself this: “How did I learn how to move my hands or legs?”</p><p>As time passed after you were born, you realized you had limbs. Great! you have limbs, now what? did you have as much control over them as you have now? Maybe you can drive a car, cook a meal or draw really well right now but were you able to <em>direct </em>your hands to perform those tasks after a few months of being born?</p><p>You made all sorts of silly gestures and flailed your arms uncontrollably, until you realized that you had gradually gained control of your arms and legs. That is what I mean by “<em>These skills are developed as you use them</em>”. Soft skills are natural.</p><p>Anyways, lets talk about the things you need to do.</p><h3>1- Diary Keeping</h3><p>I didn’t always write a personal diary, but I did like to make a record of “special things” in a day. When I got a job, everyday became a special day for me. A new morning with new possibilities. The sun shining, the flowers smiling …. no not exactly like a Lala-land but it was exciting nonetheless.</p><p>So anyways, I started keeping a diary. Where you ask? Well … I was using Ubuntu in my workplace and there is this notepad tool I really love called <a href="https://www.giuspen.net/cherrytree/">Cherry Tree</a>. It has a nice feature to maintain all my notes in a tree-like structure in a single file with rich text formatting. I had setup my tree to look something like this:</p><pre>Year: 2023<br>|- Month: Jan<br>  |- Day: 01 &lt;-- this is a &quot;date node&quot;<br>  |- Day: 02<br>  |- Day: 03<br>  |- ...<br>  |- Day: 31<br>|- Month: Feb<br>  |- Day: 01<br>  |- Day: 02<br>  |- Day: 03<br>  |- ...<br>  |- Day: 29</pre><p>Inside each date node I had a separate note in which I would write about the events related to that day. I would not write <em>everything</em> like a micro-managing maniac, just some important events, if any.</p><p>For example;</p><ol><li>If I had a meeting with HR regarding my outstanding documents which needs to be submitted into the company’s records, I would make a note of that.</li><li>If everyone in the dev room (room for developers) had a quick round of CSGO, I would make a note of that.</li><li>If I encountered a bug that messed with me for 4 hours, I would make a note of that as well.</li></ol><p>The first example had something to do with reminders, such that I would easily be able to recall in which day I was reminded or submitted the documents. The second one was just for fun. The third one however, will be able to remind me (in detail) how I solved a specific bug in a specific use case. And that is important.</p><p>It is important because at the early stages of my career I faced lots of problems, and I needed to remember exactly how I solved those problems because you can encounter a single problem multiple times when you are junior or are tasked with training juniors. It’s a one-to-many relation.</p><p>But once you encounter one problem too many times, it becomes your second nature. In other words, you become one step closer to being a senior … developer, that is.</p><p>As for the first use case I discussed earlier, I think I still have some explaining to do. I really hope not, but if your first ever workplace turns out to be toxic and HR is trying to pull your leg one way or another, you will need to keeps your wits about you. That is where keeping notes about reminders and office-related event comes in handy.</p><p>Not that my first workplace was toxic, but I kept notes about stuff because I personally wanted to optimize my routine. Like manage how much time I spend on working and slacking off. But if you have a micro-managing boss you can rest assured that you neither need a diary nor to optimize your routine (as something ‘extra’) in the office. Those things <em>will become a part of your work</em>. No kidding, but let’s hope you get hired in a great working place.</p><p>In each date-node, I would categorize things like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/818/1*e-67XsnksLVz31f99KmpXA.png" /><figcaption>My sample daily notes I took as a junior dev</figcaption></figure><blockquote><em>📌</em> I wrote the above sample in markdown to make it simpler to understand. Cherrytree stores the rich text formatted content in XML.</blockquote><p>By looking at the above sample, you can guess that I didn’t have any problems remembering what happened when and what did I do and when… you get the point.</p><p>Just don’t show it to anyone. If your boss hears word of this, they might get ideas about micromanaging. This is for you and ONLY you. You have been warned 😬</p><p>If you want, you can even put in start time and end time in each TODO item to know how much time each task took. Feel free to make this format more sophisticated or simplify it down to suit your needs.</p><h3>2- Building Rapport</h3><p>Now I know that, some of you may be an introvert and cannot keep up with lengthened durations of socialization. But even if you are an introvert, a little communication with your co-workers never hurts. Heck, even <em>I</em> am an introvert, but I have respect among my peers because I have clearly <em>communicated</em> my values and authorities to them. It was tough, but it paid off not only in establishing my position as a good person but also for upgrading my skills and career.</p><p>Think of it this way: you got hired to do a certain job and communication is a major part of a software engineer’s job. Without it, how are you going to get your requirements or ask if some instructions are unclear? Moreover, there will be meetings and it will be really great for you if you could put in some of your own inputs to the topics being discussed. You need to be able to talk to others without freaking them out.</p><p>But how does one communicate? Are there certain rules at play? Well yes, but not only in the office scenario, but also everywhere else.</p><p>For example, you go out and see a dirty guy with un-ironed clothes who probably hasn’t taken a bath for a long time now and a well dressed guy who maybe does not wear a perfume, but is clean and looks well maintained. Who seems more approachable to you?</p><p>The things is, not only your <em>words</em> but also how you <em>look</em> and <em>act</em> matters and it is in fact the <em>first ever communication</em> you do with everyone else. Before they even greet you, they judge your body language. Is it inviting? is it friendly?</p><p>Don’t worry if your face doesn’t match their ‘beauty standards’. Don’t worry if you are less knowledgeable than others. These things don’t matter in business anyway. What matters is if you can bring value in the company you are working for. This includes making the environment more friendly and inviting.</p><p>If you don’t have many friends, now is your time to make some. Since introverts often need <em>clear instructions</em> (I needed them too 😁) on the ‘how’ and ‘what’ when socializing, this is for you guys:</p><p>Greet people properly and try to talk about similar interests you both might have. If you can not find any similarities, try talking about a book that you have been reading or talk about one of the recent Fireship’s Code Reports or anything is particular. Tell them you have found it interesting (which hopefully you genuinely do) and that you are looking forward to what comes next. This way you are essentially talking about your own interests while inviting the same interests from the other person. If they don’t seem interested in your yap, then <em>now</em> you can ask them about themselves, their hobbies, what they like and what they don’t.</p><p>Remember that people are more likely to tell you about themselves if you have told them about yourself first or if they are in an interview where you are interviewing them. Going straight up and asking people about themselves may go wrong if it is your first point of contact.</p><blockquote><em>📌</em> Honestly I could add more to these instructions but that would make this article extra lengthy (which I don’t want). So instead I’m open to talk about how you can improve your communication skills on discord (username: blankscreen.exe). I usually help people from Reddit prepare for interviews and help them get a job.</blockquote><p>As a junior dev you are obviously going to work under a senior. That senior should be your first friend because it is easy to get to know someone if you are in constant interaction with them.</p><p>Your goal is not to sell yourself here like you do in an interview. It is certainly not to look charming and eye-catching. You goal through communication should be to let yourself known among other employees and present yourself as approachable and a sensible person.</p><h3>3- Asking Questions Never Gets Old</h3><p>This leads me to another important topic and it goes without saying. You need to ask question and not be afraid to ask them. You are in a junior developer position <em>because</em> you don’t know certain things. Also keep in mind that at any point in your career, no one can judge you for asking questions, but you need to be respectful.</p><p>Your seniors might already have their hands full. It will reflect bad on you if you just ask questions without doing your own research first. It’s like finding the easy way out without putting any effort into your work. This, as any sane person may think, it not appreciated in a professional setting.</p><p>Personally, when an intern or a junior asks me a question about a problem, my first reverse-question to them is, “so what have you tried?”. That is because I want to see if they have <em>actually </em>put in some effort before calling me out of my work. I do not care if their efforts were fruitless. I will happily solve their problems with them if they are willing to do some work.</p><p>If the seniors tell you to wait before they come to you, you shouldn’t just wait idly doing nothing. Try and look for a solution on your own. You have Google, you have Stackoverflow and of course CrapGPT which might not always give you solid good directions but works if you are asking for basic syntax, or something trivial like “how to center a div”.</p><blockquote><em>📌</em> I tried using CrapGPT for a month, but long story short, I wasn’t getting much value from it. So I resorted to going back to stackoverflow or official docs. Maybe I will write something on my experience with CrapGPT.</blockquote><p>It would be much better if you first did your research about a problem from different sources and then if you still don’t find a proper solution, you should ask a senior for help.</p><p>This is something that can get you laid off if you don’t properly respect and value other’s time. Your seniors are not <em>necessarily</em> there just because they are good at their work or they are happy doing it. They have a livelihood to earn and if you cannot value that, then your recruiter will probably start to have doubts in the potential value you are bringing to the company.</p><blockquote>As for me, 😁 I love doing my work, but I don’t appreciate it if someone disrupts my flow for no reason. I don’t mind mentoring as this is also a part of my job. But I would rather not spend time doing something that I am not supposed to do. No one wants to be caught sulking around doing something useless during working hours right?</blockquote><p>I will now emphasize on the importance of asking the right questions. What you don’t want to ask are questions like these:</p><ul><li>How do I solve this error?</li><li>How can I implement custom authentication?</li><li>How does the request lifecycle work?</li></ul><p>Notice how these questions fail to show what effort you have put in your work before jumping on someone’s head for an answer. Also notice, that these questions are basically prompting others to do <em>your own work</em> for you, which, in all honesty, you should be doing. By asking these types of questions, you are clearly showing that you don’t have enough ability to Google some simple stuff like custom authentication and request lifecycle in this example. Stack overflow is overflowing with answers to this and all directly related questions, yet somehow you managed to look past all that and chose the superfast and easy way to bug a senior dev.</p><p>Do not ask for things which you easily get an answer to if you google a little bit. Yet simple things can be complicated for juniors, and I understand that. Therefore, you need to be able to show your research and discuss the things that you have tried before you can ask for help.</p><p>This should not discourage from asking too many or dumb questions. Questions are <em>always appreciated</em>, as they show your willingness to learn. But you need to be mindful about asking the proper questions and back it up with evidence of your efforts.</p><h3>4- Ask To Participate In Code Reviews</h3><p>Asking to participate in code reviews and debugging existing problems is a great exercise if you want to get familiar to a project you are working on. In fact, you will most probably get debugging as your first ever task as junior dev. So in most cases, you wouldn’t even have to ask to participate.</p><p>If you are doing it yourself, then you will have ample opportunities to learn how the project is working under the hood and also observe how the project is structured by your seniors.</p><p>If you are observing a senior do it, then you will have an opportunity to learn how <em>they</em> do it. Which files do they start with? and how do they track a bug to its source? How are they handling a bug? All of these things are what you should be looking out for when observing a senior do their work. You don’t just need to observe, this is actually a good place to start questioning too!</p><p>During debugging and code reviewing, you will find yourself collecting an arsenal of questions, some of which may be impressive and some just plain stupid that even you can answer after some Googling. Save the tricky ones for your senior and the easy ones for yourself. This is also where diary keeping skill comes in handy.</p><h3>5- Ask For Time When Doing Something New</h3><p>We all believe that an opportunity can arise at any given moment and surprise us. This is also true if your supervisor suddenly appears out of nowhere and tasks you with building something out of a technology you have absolutely no clue about. This can happen with equal probability for seniors and juniors alike.</p><p>If you ever saw someone telling your senior dev to build something using a new technology, they will always <em>estimate some</em> <em>time</em> during which they will be learning about this new technology and convey the estimations to their higher-ups.</p><p>Truth be told, some companies readily give out “learning time” if they want one of their resources to work on something new, because they understand the importance of <em>proper</em> work in contrast with <em>makeshift</em> work.</p><p>On the other hand, as you might have guessed, some companies don’t allow for such time. This difference is simply due to the lack of resource management and planning capabilities in a company’s management department, but unfortunately, it happens all the same.</p><blockquote><em>📌</em> Honestly speaking I could rant all day without breaking a sweat about these companies who don’t allow “learning time”. I can go into intricate details about what goes wrong and where. But it is not in the scope of this article.</blockquote><p>So the take here is to politely ask for some time (from your normal working hours) to learn something new. This request of your should always accompany time-estimations, which are important because it shows that you have done your research about a technology and broke it down into organized hierarchy of milestones and that you have planned your learning journey properly. So now people won’t think that you are just blabbering a number, but you are backing it with proper evidence of how much effort you are going to be putting each day.</p><p>One good way to do this is … let me just tell you through an example:</p><p>Assume that your supervisor shows up to you and asks you to learn about MongoDB, because that is what you will be using in your next project. You will tell the supervisor that you will look into it.</p><p>Your next move should be to search for online resources that teach MongoDB. In this scenario, you will find that they have a Mongo University which covers everything you need to know about Queries, Compass and Mongo’s driver code etc.</p><p>You will review the time estimations for that course and add some extra time to it. You will tell your supervisor that it will take X hours to learn about this technology in order to be able to actually use it.</p><p>Now there are 2 things that can happen:</p><ul><li>You supervisor approves of it and you start learning.</li><li>Or your supervisor suggests you some other alternative course/mini-project and you work on that … with time estimations.</li></ul><h3>6- Time Management And Deadline Estimations</h3><p>I talked about adding some extra time up there. Let’s discuss how we actually estimate timelines and how will we manage our time according to our estimates and deadlines.</p><p>First about the estimations; when your supervisor relays some tasks to you, you will almost always be asked to estimate timelines for each umbrella activity and its sub tasks.</p><blockquote>In case you don’t know Umbrella Activity is a combination of several tasks which are required for a certain feature to work. For example, adding a like button to posts is an umbrella activity. It will have sub tasks such as modifying database to record number of likes, changing frontend etc.</blockquote><p>If the project you are working on is being created from scratch, you will have a chance to witness how the timelines are being set by your seniors. You might not need to manage a Gantt Chart or plan time estimates at all for overall projects because that is what the senior developers and project managers meet up for.</p><p>But the supervisor might still come to you with some tasks, that they plan to give you, and ask your opinion on how much time should a specific task take (if you were to do it, instead of someone experienced).</p><p>The thing is, they understand that you as a junior developer will take some extra time to understand stuff before doing it, as compared to senior developers who will plug this, slap that and call it a day. Therefore they would want to know how much time you want to take doing your stuff independently.</p><p>By this you can infer two things:</p><ol><li>Time estimates are NOT objective, it is in fact subjective. It depends on the person doing it.</li><li>It is NOT a given that a certain task will always take a certain amount of time.</li></ol><p>And this brings up a good question: <em>how do we know how much time will we take when we do a certain task?</em></p><p>The answer to that is, you can never know the duration you are going to spend on something. Anything can go wrong at any moment. You never know.</p><p>So what do we say when we are being asked about time estimates?</p><p>Think of your time estimates like “How much time am I willing to spend on this task?” rather than “How much time will it take?”. That is how the seniors do it.</p><p>If you want to include in some time for research before you actually do it, tell them about it and the hours you are allocating for the research. At the end, after you have finalized your time estimates, add another 10% to 15% of the total time as a buffer. This buffer time will act as a 1UP if you are not able to meet any of your deadlines for any reason.</p><p>Now that you have given your time estimates successfully, lets talk about how to manage time so that you can meet your deadline which you yourself have set.</p><p>You might have heard about <a href="https://en.wikipedia.org/wiki/Pomodoro_Technique">Pomodoro Technique</a> or <a href="https://en.wikipedia.org/wiki/Timeboxing">Time Boxing</a> etc. While these are good techniques which can be used outside of software engineering, but they are quite a hassle to work with. These techniques promise you a healthier work pattern, but at the cost of your <em>attention</em>. Attention is something 99% of which you would rather spend on your actual work, than on managing your work.</p><p>You can try it yourself, use pomodoro technique, work 25 mins and rest 5 mins. Do this in a loop until your day ends. Or you can try time boxing and set strict time frames for each day’s tasks. You would soon find yourself managing your work pattern more than doing your actual work which you were hired for. And yes this might not look good on you from your supervisor’s perspective.</p><p>While these techniques are good on their own, I personally haven’t benefitted from them after trying them out. Let me know if there was a technique that worked for you down in the comments.</p><p>As for me, I used to take tasks assigned to me by the project manager, and planned on doing one or two of them in a single day. I was a bit slow but it was understandable and I was producing results independently so no one bothered me much. But deadlines were still strict, because that is something coming from the client themselves.</p><p>A good thing you can do is take your tasks seriously. Everyone expects you to get stuck finding a solution to something. They know you will take some extra time doing normal stuff. However deadlines should be taken seriously.</p><p>I remember myself trying to figure out something in and out of working hours. Some of you might have an ego about not working after office hours but at this stage, you should worry about your growth even if you have to work some extra. Of course there is a limit after which extra hours become bad for your health so take that into consideration as well.</p><h3>7- Discuss Your Potential Growth</h3><p>This is one of the things you can do to show that you are willing to bring value to the company as you seek out further growth opportunities. After all you can only contribute better to the company if you grow or climb up the corporate ladder.</p><p>You can discuss about your growth (either in your responsibilities or your role) with anyone, but I would recommend that you ONLY do it with your direct seniors or their leads. This is because any other person, especially if they are not well-known in their field or rank close to you, would consider it as a competition and that is when things get dirty.</p><p>But we are going to assume a workplace which is free of politics and think straight. I am not preaching about office politics here anyways.</p><p>Assume that you are a lead engineer in a huge project and are being paid in millions to oversee the project (hopefully this assumption is true in your future). Now there are two juniors who are working under you.</p><p>Junior A is shy but excels in his field. He knows what he is doing and will do absolutely anything you ask of him. He does often get stuck in things, as juniors always do, but with minimal support, he can get back on his feet.</p><p>Junior B, however is not shy, but not very social either. He would greet people nicely and thus, became a familiar face in the office. He is not as much proficient as Junior A, but he makes it clear that he is willing to learn anything and produce quality results.</p><p>One day, both of them come to you and pose their questions like this:</p><p><strong>Junior A</strong>: “<em>I have been doing mediocre work for a while now and I am looking for challenges. If you can, please allow me the opportunity to take on additional responsibilities.</em>”</p><p><strong>Junior B</strong>: “I have been thinking about upgrading myself in the right way so that I can contribute better. This has been on my mind for a while now. I’d like to know what can I do to better myself and what pathway is available for me.”</p><p>Now think <em>really</em> hard from a lead’s perspective! Which junior deserves a higher position in the corporate ladder and hopefully an increment in their salaries?</p><p>If you were thinking that this is a game where one person wins and other looses, then you are dead wrong. Psych! Both of them are deserving.</p><p>From a lead’s perspective, you can see that they both are willing to upscale themselves and genuinely rise to new heights in their own way. One wants to take on additional responsibilities and other wants to learn something useful. The biggest similarity is, they both are ASKING FOR IT from you, the lead engineer.</p><h3>8- Accountability</h3><p>You are going to make mistakes, that is a given. If you are thinking that senior developers are smart people and don’t make mistakes, then you sir are definitely wrong. As long as anything is living on this planet or the next, they will definitely make mistakes.</p><p>With that said, you are going to be judged by your mistakes as well as your accomplishments. There are two types of people who are going to judge you: Those whose judgment matters in your next salary review, and those whose opinions are just for themselves to feel good about.</p><p>In that regard, your supervisor’s image of you is definitely going to matter. Now I am tired of making comparison scenarios when I tell you about two people and ask you to compare them. So I will just cut to the chase. Believe me if you like.</p><p>If you try to blame others it is not going to reflect good on you. Even if it genuinely is someone else’s fault, still don’t blame anyone. You don’t want your co-workers ganging up on you in an alleyway.</p><p>Instead, volunteer to solve the problem or help solve it (if you do not have any other tasks of your own).</p><p>If it is, in fact, your own fault, then be quick to respond to it. Ask them the details of the problem and start debugging it like a good boi.</p><p>People want to see if you are a “problem solver” and not a “problem deflector”.</p><h3>9- Mindset</h3><p>Programming requires creativity, and creativity is about using the tools you have, in order to achieve a goal. Your methods can be unconventional but they do solve a problem. Since this creativity relies on the tools you have at your disposal, your creativity will grow as you knowledge of your technologies grow.</p><p>This field of work is for those who are curious. There are many technologies in the wild, that NO ONE person can know about all of them. You might know about some, but not all.</p><p>Curiosity is a tool which enables you to develop hunger for knowledge. But it can be troublesome if not given a proper direction. Afterall, eating the wrong kind of stuff can be bad for your dietary goals.</p><p>I know, I know … me an my stupid analogies. But you get the point.</p><p>If you let your curiosity run in the wild, it will hop on topic after topic without doing anything meaningful. If you don’t put a leash on your curiosity, it will start running like a wild horse, will be difficult to control.</p><p>I said that you need a direction for your curiosity. This means you must have a plan or a roadmap about which topics you are going to learn and which topics you are going to skip.</p><p>If you are learning from youtube, then know this that the youtube’s algorithm will try to feed you topics that will of course pique your interest but will be useless for your learning goals. That algorithm is not trained to feed you what you <em>need </em>but instead it works for <em>maximizing views </em>and engagement. It’s a deception.</p><p>I am not saying that you will not learn anything useful that way, but it cannot be called <em>guided learning</em>. Guided learning is when you have a curriculum that you follow to the end to gain knowledge about a certain topic. That is being followed in all the educational institutions, and that is what makes a huge difference between self-taught developers and ones with a degree (assuming they both tried to make good use of their time).</p><p>For roadmaps I will always recommend <a href="https://roadmap.sh">roadmap.sh</a> unless I find a better alternative. This should give you some proper direction.</p><p>Another thing about your mindset, is that you should be humble. I don’t care if you have the ability to make the next facebook or google. If that were the case, you would not be hired as a junior developer.</p><p>I am certainly not discouraging you and stopping you from making the next facebook. But I want you to get rid of your ego and over-confidence. I want you to be <em>realistic</em>.</p><p>If there is something you have not done before, but you think that you could just give the docs a little read and be able to do it, then no, it does not work that way. You will most probably get stuck in an error and <em>use </em>some of your time debugging it. Notice how I said “use” instead of “waste”, because that is still a part of learning.</p><p>What do you think makes a senior dev a senior developer? The answer is <em>mistakes </em>and lots of it. Why do you think that you automatically assume that senior developers will have an answer for the bugs YOU are seeing on YOUR screen? The answer is because they have seen those bugs many times now and have solved them over and over again. They ran into those bugs because they made mistakes.</p><p>This is also an important part of accountability as I previously discussed. You should not be ashamed of accepting your mistakes, but be eager to learn how to fix them. It is completely OK to say “I don’t know about this”, at all stages of your career. Because this is what opens up a path for learning and growing.</p><h3>10- Burning Out Is Not A Good Idea</h3><p>It is a marathon, not a sprint. Only the wise understand this and conserve their energy, enthusiasm and attention in order to spend them wisely. A lot of bad things will follow if you get burned out. You would not have enough sleep to properly function let alone code, you will not have the capacity engage your attention anywhere, you will feel like sh*t all the time. Honestly I could give you more reasons why not burn yourself out, but that would be another blog article on it’s own.</p><p>If you burn yourself out, you will definitely miss out on the wealth (as in your salary) and the wealth of knowledge you could have taken if you were not half dead inside. This adds yet another meaning to the proverb “Health is wealth”.</p><p>Staying healthy and hygienic is as much important as arriving on time for your job. Take baths daily. Stand up from your chair and walk around a little bit. Eat less junk. Don’t stare at your screen for hours, and look away around you. These tiny actions can make a lot of difference.</p><p>You can never compromise on your health, even if the job demands it.</p><h3>11- Think Of Software Engineering As A Craft</h3><p>No one seems to preach this, yet this is as important as it gets. during your career, you might think of dropping out because you are good at it, maybe you think you have <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">imposter syndrome</a>. These kinds of discouraging thoughts are common.</p><blockquote><em>📌</em> SWE = SoftWare Engineering</blockquote><p>What you need to understand is that Software Engineering is a <a href="https://www.merriam-webster.com/dictionary/craft">craft</a>. Like any other craft, it will get easier and easier as you get accustomed to it. How do you get accustomed to SWE? Practice of course!</p><blockquote><em>📌</em> All of the rules that apply on any given craft, is applicable on SWE as well.</blockquote><p>Practice is what makes you a master in any given craft. So why not make use of it to become a master of your own craft (which is smashing buttons on a keyboard all the time)</p><p>But now the question arises: practice <em>what </em>exactly?</p><p>A good portion of what you will do in your job is problem solving by building your own algorithms and then translating it into a programming language of your choice. The “building your own algorithms” part is where you need to focus on because that is core of your purpose as a developer.</p><p>There are many ways you could practice code. There is <a href="https://leetcode.com">Leetcode</a>, <a href="https://www.codechef.com">CodeChef</a>, <a href="https://www.hackerrank.com/">Hackerrank</a>, <a href="https://codeforces.com/">Codeforces</a> etc. Just pick one of these sites and start problem solving. Always start with the easy questions first, even if you are feeling confident, just to get the <em>feel</em> of the platform.</p><p>Another way to practice code is by building pet projects. This exercise may or may not enhance your algorithm building skill, but will definitely allow you to explore technologies which you will use in your job. Use this to upgrade yourself and your arsenal of knowledge.</p><h3>12- Know Your Apps Inside Out</h3><p>It is not like you will be jumping ships every two days or so. A project that you are working on will most likely go on for a few months to years. Plus if you have spent time working on a project, then most likely you will escalate to supervisor for that specific project.</p><p>It is a cycle where your senior is slowly training you on the project so they can move onto new ones, and you will do the same for your juniors when your time comes.</p><p>Therefore it is always a good idea to explore every corner of the application you are working on. Become familiar with the technologies that are being used in it.</p><p>Remember that I talked about using some of your free time to learn about new technologies(section 11)? You should focus on the technologies that you will encounter in your currently assigned project.</p><p>This is where you should start with, when learning new things.</p><h3>13- Do Things That Make You Stand Out</h3><p>Doing things that you are supposed to do on a daily basis will not get you anywhere if you want a name for yourself. But don’t get carried away! Doing something extra does not mean that you are abandoning your responsibilities or are not working to be able to perform those duties better.</p><p>You should only do something extra, when your supervisor allows you to or when you have finished all your tasks for the day.</p><p>Now let us talk about what this “extra” actually is. This could mean that you are simply taking interest in your senior’s work or doing some extravagant like participating in critical decisions. You could, for example, ask your senior or project manager to bring you in the next meeting for some ABC Software as a bystander. There is no reason for them to decline you, but if they do then respect their decision.</p><p>If you are having trouble thinking of what “extra” you can do in your free time, then here are some suggestions:</p><ul><li>Volunteer if something new pops up. For example, your SQA raised a bug and you had some free time. So you could ask your supervisor to assign you that bug.</li><li>If you have subscribed to fireship or if you are an avid visitor of places like <a href="https://news.ycombinator.com">hackernews</a>, <a href="https://dev.to">dev.to</a>, <a href="https://daily.dev">daily.dev</a>, medium etc. You could try and share something over lunch that you found interesting.</li><li>Ask for feedback on your work.</li><li>If there is a bug, share your understanding what could be done to solve it or to improve it. You would be surprised by the variety of solutions each of your co-workers have in mind.</li><li>Talk to people outside your department. Let them know you exist and that you are a good person to talk to.</li><li>If something feels within your expertise or skillset, offer your help on those.</li></ul><p>Notice that most of these things are what I already told about in previous sections. Turns out that I was secretly planning to make you stand out and out grow your role 😁.</p><h3>14- Show Empathy While Writing Code</h3><p>Some of you might have that sudden and unquenchable urge to write clean code. If this happens, then you would certainly strive to become the very epitome standards and radiant efficiency.</p><p>You guys should know that most of what the clean code preachers say are a scam. At the end of the day, your code either makes the client or other developers happy.</p><p>If it is making the client happy, then your code is performant. If it is making other developers happy then your code is clean enough to work with.</p><p>But this new found urge of your can also be your downfall. It can turn into a tyrant that no one wants in their team. Allow me to elaborate:</p><p>When you are being assigned to a new project then it is not just a project that you are going to work with. It will also be the hopes and dreams of a “genius” person who started it from scratch.</p><p>Now you generate your very first pull request and your senior does not have the slightest idea the torment he is going to face. When he opens it for reviewing he sees the following:</p><ul><li>Every line of code has a comment above it which explains the line of code does.</li><li>Onslaught of incredible one-liner code.</li><li>A new file is created for every helper function.</li><li>Excessive tests are written for each micro functionality.</li></ul><p>The senior sees this much and rejects the pull request out of his horror. who knows what other monstrosities were in there? Here is what was wrong:</p><p>The comments are good but should be rarely used since the code should be self explanatory. Several proper code enthusiasts forget that. Also, what if someone changes the keywords used in the line of code? Now the code might do something different and would not fit the description which you put up there. I am this case your comment would be explaining a scenario that does not exist anymore. It would be a lie. You could argue that the person changing the code could rewrite the comment or remove it. But would you yourself want to work to work on someone else’s code where you have to put in double the effort to perform a single task? Time is money which the client’s are always counting.</p><p>One-liner code are great for flaunting your superiority complex. But do they make the code less readable? Yes of course. Other people who are going to work on it will have to break it down which can frustrate them. Afterall, software engineering as a whole can be a really frustrating exercise. Don’t get me wrong though, there are certain scenarios where you must use a one-liner either for efficiency or for a functionality to work properly.</p><p>Modularity is good to include in your code where you categorize related classes or functions in different files. But then you could easily be a victim of “modularity hell” as I like to call it. You will soon find out that each class/function is distinct and you will end up giving each of those classes/functions a category of their own. You need to learn to compromise a bit when it comes to modularity.</p><p>100% test coverage, as far as I see it, is a myth. The main idea for test driven development is to write minimal tests and then write the code that passes those tests. So we usually only write tests only to check if the requirements are working fine, that is it. writing excessive test not only forces you to give more time writing tests than actually writing the code that matters the most to the client.</p><p>One more thing that juniors often do not take into consideration is the standards. They tend to introduce their own into the codebase. If you see a standard being followed for whatever stupid reason, just follow it. Someone more experienced than you put their time and efforts to create those standards in a single project, whether it is for importing models or inheriting custom classes. No matter how unconventional the standards may look, just follow them.</p><h3>15- Restrict AI Chatbot Usage</h3><p>Almost 99% of the juniors (I could be exaggerating this number) I see today, whether in the company I work for or others, frequently use AI in their workplace. Is this bad? Well, for the most part my answer is going to be yes.</p><p>The reason behind this is simple, think about teaching your kids to use a calculator for even the simplest of calculations. Now that they have a habit of doing this, so much so that it has become a major part of their lives, they will be whipping out a calculator for even the most trivial of sums.</p><p>When their calculator malfunctions, they in turn also give out wrong answers. When their calculator’s batteries die, they panic because now they are unable to calculate anything. Turns out they have been <em>overly dependent</em> on their calculators that they simply forgot to use their brains.</p><p>Another analogy I would like to give you is that of a FPS shooting game. If you are overly dependent and abuse the usage of <a href="https://en.wikipedia.org/wiki/Cheating_in_online_games">AIM BOT cheat</a>, you will never develop the skill for aiming yourself.</p><p>Like every other tool, these AI chatbots have their good usage and bad usage. Beginners and juniors alike generally use them in a bad way.</p><p>Yes it can increase productivity (I personally cannot vouch for that though), but that depends on how the chatbot is used. If you throw all the <em>logic building</em> towards the chatbot and use your brain for Ctrl+C and Ctrl+V, then you did not grow, you did not learn anything, but what you actually did was to burn the bridge which leads to “being an experienced developer”.</p><p>Generally speaking, these chatbots are more useful in the hands of senior developers than it is useful for juniors. Juniors are there to learn stuff, that is what they should focus on while contributing to projects.</p><p>Juniors nowadays need to understand that there were legendary programmers before these chatbots were even a concept. How did they become the legends? They didn’t sulk around generating code, that much I can tell you.</p><p>Yes you can use it for ideas like how should you structure your database and for syntax problems like which method to call from a pre-made class. I do it in my work so I encourage you to do so too. But what I fear the most is that the line between good usage and bad usage is very thin and often blurred when it comes to these chatbots.</p><p>Another of my fears, is that you never give a weapon to someone, not until you have trained them how to use it at least. The reason why I am using such a grave analogy here is because it can potentially ruin careers of people. Think of someone who have used these chatbots for an year now. If they go to a recruiter there is going to be an interview. Will they be able to answer those questions?</p><p>It all boils down to how the tool is used, and sadly most people often like to go for the easy and convenient way.</p><p>Not to mention that the practice of using a chatbot with sensitive data can be subjected to violation of company’s or its client’s privacy.</p><p>You need to have a little confidence in yourself. You are better than the chat bot. Your seniors are way better than you. You have lots of other options. Be dependent on your wits rather than on a chat bot.</p><h3>Final Word</h3><p>These were some of the things I did while I was a junior or at least think that I should have done.</p><p>While some of the ideas I gave you are good on their own, your situation might vary. So feel free to use your creativity to make the most out of your career.</p><p>The list of advice I have here, is obviously not complete, but it is a good compilation of my personal journey as a software engineer. If you have any ideas of your own or deferring thoughts on any of my ideas that you would want the junior developers who are reading this to know, then please do comment below. It might do some good.</p><p>Above all else, soft skills matters more than writing code.</p><p>Lastly, some of the great points in this article are due to some very generous people from Reddit r\AskProgramming. I would like to give them my heartfelt gratitude. It is because of these people that programming aspirants have someone to rely on.</p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>You now know the recipe for success. Go out there and win the world.</p><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to listen to your feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2c65057b4bf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Useful TMUX Plugins Which I Frequently Use At Work]]></title>
            <link>https://medium.com/@dev-in-trenches/useful-tmux-plugins-which-i-frequently-use-at-work-41a9b46f7bcb?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/41a9b46f7bcb</guid>
            <category><![CDATA[workflow-management]]></category>
            <category><![CDATA[terminal]]></category>
            <category><![CDATA[developer-tools]]></category>
            <category><![CDATA[tmux]]></category>
            <category><![CDATA[plugins]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Wed, 07 Aug 2024 20:13:28 GMT</pubDate>
            <atom:updated>2024-08-21T05:36:27.521Z</atom:updated>
            <content:encoded><![CDATA[<p>Looking forward to expanding your arsenal in TMUX? I can tell you which weapons to choose and where to use them.</p><blockquote>📌 I wrote this one since some people have been asking for it. Hope you will like it.</blockquote><p>So if you have been reading my previous articles then you would probably know that I work as a Software Engineer where my responsibilities include working on projects from scratch, collaborating on ongoing projects, debugging, containerizing and deploying stuff on cloud and who knows what sort of shenanigans I’m up to.</p><p>So now that you have a picture of what I do on a daily basis, you can relate yourself to me as we go on exploring these TMUX plugins.</p><p>If you want a refresher on TMUX, I have explained how to approach learning it in a human-friendly way, as it can be a daunting task:</p><p><a href="https://medium.com/@hammad.ai/how-i-learned-tmux-became-a-workflow-ninja-7d33cc796793">How I Learned TMUX &amp; Became A Workflow Ninja</a></p><p>Enough jibber-jabber, let’s get down to business … here is what you should expect from this article:</p><p>1- First, I will explain how to install and use any plugin.</p><p>2- Then I will open up a pandora’s box of TMUX plugins and go through each one.</p><p>3- I will also be telling you how to <em>make your own</em> TMUX plugins.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*YFqlTszYpVHQcFayo5-l2g.png" /></figure><h3>How To Install TMUX Plugins</h3><p>There are mainly 2 ways you could do this:</p><ul><li><strong>Manually 👉</strong> Download the plugin code yourself (<em>git clone it</em>) and place it in the appropriate directory. You’ll then need to configure your tmux configuration file .tmux.conf to reference the plugin.</li><li><strong>Using THE plugin manager 👉</strong>A plugin manager automates the installation and management of tmux plugins. <a href="https://github.com/tmux-plugins/tpm">Tmux Plugin Manager</a> (TPM) is a popular choice that simplifies the process considerably. You can install and update plugins directly from your tmux configuration file .tmux.conf.</li></ul><p>I’m not going to explain any of the above methods, since you can already find a resource online which tells you how to do it. Let’s move onto the more exciting and fun part.</p><blockquote><em>📌</em> But in case you encounter a problem while setting up Tmux Plugin Manager, the best I can do is reply to your queries in the comments.</blockquote><h3>List Of Plugins</h3><blockquote><em>📌</em> The order of these plugins are not meant to be ranked. They are randomly ordered.</blockquote><p>All the plugins shown below can be seen <a href="https://github.com/tmux-plugins/list">officially listed here</a>.</p><p>There are 3 categories in which I personally divide the plugins:</p><ol><li>The <strong>essentials,</strong> which I use on a daily basis</li><li>The <strong>flex-material</strong>, which … well … is used to flex ofc</li><li>And some <strong>miscellaneous</strong> stuff, which might be useful in very specific contexts, but using them really depends on if you’d like to or not.</li></ol><p>The first category is what I’m listing below.</p><h4>🟢 <a href="https://github.com/akohlbecker/aw-watcher-tmux">aw-watcher-tmux</a></h4><p>I used this simply because I like to keep a log of my activities. aw-watcher-tmux can not only be installed as a TMUX plugin, but can also work as a global application which runs as a service. Not only that it can also work on Mac, Windows, and of course Linux.</p><blockquote><em>*</em>takes in a deep breath<em>* I use </em><a href="https://archlinux.org/"><em>Arch</em></a><em> by the way </em><strong><em>😎</em></strong><em> …</em></blockquote><blockquote><em>… this is something I’d like to say at this point in order flex on you as a developer, but it’s a lie though. I use Ubuntu. Maybe I’ll write something about getting used to Arch Linux someday too. Let me know if you would be interested.</em></blockquote><p>Getting back to the topic …</p><p>In case of TMUX it keeps track of the sessions and activities inside those sessions. In case you are thinking about tracking the activity of a certain user, then no, it cannot categorize activities with respect to each user on a machine. And it shouldn’t, because that is a violation of privacy.</p><p>It is supposed to be used for productivity, not as a spyware. Therefore every data stays local.</p><p>Also it comes with a pretty UI in the browser so that is a plus. But don’t let your boss know about it, because they might start <em>micro-managing </em>you.</p><p>Here is the <a href="https://activitywatch.net/">official website</a> in case you are wondering.</p><h4>🟢 <a href="https://github.com/b0o/tmux-autoreload">tmux-autoreload</a></h4><p>This is basically a “file watcher” designed for tmux.conf file, just like git watches files for changes.</p><p>It watches our configuration file and automatically reloads it, applying the latest settings right away. This saves me the trouble of reloading configuration manually every time I update it.</p><h4>🟢 <a href="https://github.com/tmux-plugins/tmux-cowboy">tmux-cowboy</a></h4><p>It is designed to help you terminate unresponsive processes running within your terminal sessions. This is a quick and easy way to “kill” those CPU hogging programs that have become stuck or frozen.</p><p>Its main feature is its ability to kill processes, which it does by sending a <em>fastest </em>SIGKILL <em>signal in the wild west </em>to the target programs. The good thing is that it saves me the trouble of switching to another pane/windows to kill them myself.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*ExPJf8k1RucK8LFt9qzrxg.gif" /></figure><p>But here’s a catch: It is not for noobs who just started learning how to use Linux based systems. You must be able to understand the <em>risks</em> that come with this plugin or else you will <em>break something</em> you shouldn’t have. It can also lead to data loss or unexpected behavior if the process hasn’t been properly shut down.</p><p>I would only recommend using this ONLY IF your process is completely unresponsive, other termination methods have failed, and when you know what you are doing.</p><h4>🟢 <a href="https://github.com/thepante/tmux-git-autofetch/">tmux-git-autofetch</a></h4><p>As the name suggests, it auto fetches from remote git repository so that you don’t need to run git fetch everytime. I personally felt it very annoying when I commit some changes only to find out that the REF I’m pushing to has changed. So this plugin acts as a good reminder as well.</p><h4>🟢 <a href="https://github.com/jaclu/tmux-menus">tmux-menus</a></h4><p>Having trouble remembering all the key-binding which you yourself assigned? Say no more.</p><p>This plugin is the TUI solution for context menu inside the terminal. All you need to do in memorize one single key binding for tmux-menus. It presents the user with a popup context menu which handles all the hard-to-remember key-bindings in the backend and let’s you choose what you need to do. This is what it looks like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Tjc7wC-FeMdACdPFBYkCAg.png" /></figure><p>The menu you are seeing above is just the main menu. There sub menus in there as well. I really recommend you try this one, because it makes life much much easier. Also, apart from regular key-bindings, there are a bunch of custom commands you can also use.</p><h4>🟢 <a href="https://github.com/tmux-plugins/tmux-sidebar">tmux-sidebar</a></h4><p>This plugin provides you with a sidebar, which shows you your current working directory and, recursively, their inner contents and the contents of their subfolders.</p><p>This sidebar acts just like a pane, which cannot be interacted with, other than by using arrow keys to scroll through a mess of your directories.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z0yFnCtldgs4Mtfny_Lo5g.png" /></figure><p>On the far left is my sidebar. You can navigate to it just like you would in a normal pane i.e. prefix + &lt;arrow_keys&gt;.</p><h4>🟢 t<a href="https://github.com/tmux-plugins/tmux-sensible">mux-sensible</a></h4><p>As the name suggests, this plugin introduces a set of standardized settings to TMUX. The reason why I consider this <em>standardization </em>necessary is because, I mostly work on remote servers with several other people. That is where this standardization comes into play.</p><p>Using this plugin, everyone can stay on the same page and won’t be pinging others or reading the tmux.conf every 2 minutes.</p><p>In my case, I haven’t made too many changes to my tmux.conf which I got from tmux-sensible.</p><h4>🟢 <a href="https://github.com/noscript/tmux-mighty-scroll">tmux-mighty-scroll</a></h4><p>Usually when you want to scroll up or down in a pane/window, you would first enter copy mode by typing: prefix + [. This plugin simply helps you do that and saves you from going into the copy mode manually.</p><p>To be honest, you can scroll quite well without this plugin in a tmux session. But if you tried scrolling with the default settings you would notice that scrolling only works similar to <em>up/down arrow keys</em> in a normal shell session outside of tmux, i.e. you will see previously entered commands (in chronological order) which will be shown against your prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/854/1*0MN_4qFJdS7CqoTqyBYHPA.gif" /><figcaption>Example of how tmux-mighty-scroll works (source: I edited this myself)</figcaption></figure><p>Remember that tmux-mighty-scroll will not work unless you enter command mode and type these magic words: set -g mouse on , or better yet, set this command in your .tmux.conf.</p><p>As a bonus, it also let’s you navigate to panes using your mouse. Just hover your mouse over a pane and left-click it.</p><h4>🟢 <a href="https://github.com/tmux-plugins/tmux-continuum">tmux-continuum</a></h4><p>The features tmux-continuum boasts about are:</p><ul><li>Continuous saving of tmux environment</li><li>Automatic tmux start when computer/server is turned on</li><li>Automatic restore when tmux is started</li></ul><p>It basically persists sessions across system restarts. The good thing is that it is <em>automagical</em>. Even the “continuous saving” part, which saves at every 15 minutes interval.</p><p>It becomes a pretty big deal if your server went down because of some idiot (hopefully not you) and you need all your sessions back.</p><h4>🟢 <a href="https://github.com/sainnhe/tmux-fzf">tmux-fzf</a></h4><p>This plugin lets you manage tmux environment. What do I mean by that? well, you can perform operations with panes, windows or sessions like for example resize panes, create new or murder old sessions and all those things you would normally do with tmux key-bindings. Think of this as a single key combination which lets you perform all kinds of operations within tmux.</p><p>Here is what the tmux-fzf menu looks like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_jdoNs0vN2cnk170uiA3Ag.png" /></figure><p>What’s more you can even manipulate/setup existing key-bindings. But wait, there’s more. See that clipboard option in that menu? You guessed it! you can reuse previously copied stuff pretty easily.</p><p>If you hadn’t already guessed, there’s a catch. This plugin comes with dependencies. <a href="https://github.com/junegunn/fzf/">fzf</a> being one of those dependencies which is basically a fuzzy-finder (search tool which uses fuzzy matches to find stuff).</p><p>Also that clipboard will not work unless you install <a href="https://github.com/hluk/CopyQ/">CopyQ</a>.</p><blockquote><em>📌</em> There are lots of other tmux plugins which use fzf. fzf itself is a nice tool. Make sure you check it out.</blockquote><p>Apart from these dependency issues, it is a good plugin to work with. especially if you are not a fan of memorizing key-bindings.</p><h4>🟢 <a href="https://github.com/tmux-plugins/tmux-resurrect">tmux-resurrect</a></h4><p>As soon my work shift is over, I turn off my PC and walk out. When I get back in and power up my PC, I see that my precious tmux sessions are gone … poof.</p><p>That is the main issue this plugin solves. It will persist your sessions even if you shut down or restart your PC. This is especially helpful when your server crashes and you need to restart it.</p><h4>🟢 <a href="https://github.com/spywhere/tmux-named-snapshot">tmux-named-snapshot</a></h4><p>This plugin works as an extension of tmux-resurrect. It gives you the ability to save and restore sessions in your system. This is just like saving in a game, but if you are thinking that you can break something and load a previously saved session, to “undo” the chaos that ensued … then no. What’s done is done. There is no retribution for you.</p><p>Also you can name the snapshot before you save it which is nice.</p><h4>🟢 <a href="https://github.com/thewtex/tmux-mem-cpu-load">tmux-mem-cpu-load</a></h4><p>This is useful when you are cutting it very close to the CPU/RAM usage of your server and you <em>need</em> to know how much memory or CPU power is being consumed.</p><p>The value of memory shown by this plugin is dynamic and changes automatically.</p><p>To use it you will have to change configuration in your .tmux.conf and add the following line:</p><pre>set -g status-right &#39;#[fg=green]#($TMUX_PLUGIN_MANAGER_PATH/tmux-mem-cpu-load/tmux-mem-cpu-load --colors --powerline-right --interval 2)#[default]&#39;</pre><p>Or alternatively you can use prefix + : to enter command mode and type in the same thing. They both will have the same effect.</p><h4>🟢 <a href="https://github.com/tmux-plugins/tmux-prefix-highlight">tmux-prefix-highlight</a></h4><p>This one only highlights when you press TMUX prefix key. The highlight is shown in the status bar below a TMUX session. It is obvious why this would be a good plugin to have.</p><h4>🟢 <a href="https://github.com/laktak/tome">tome</a></h4><p>Tome is a playbook which stores multiple shell commands. It also allows you the ability to access those playbooks and execute those commands without copy/pasting them. Sounds convenient and it actually is.</p><p>But some of you might think, “Hey we can already use <a href="https://discourse.ubuntu.com/t/how-to-use-instance-command-aliases/24128">aliases</a> for that right?” … right?</p><p>You are correct but in my case I didn’t want to store the command of importing/exporting MySQL backup databases inside .bash_aliases or when I have to run commands from a README file. I think of tome as a more organized approach to storing and executing commands.</p><p>When you access tome using prefix + shift + p, it creates a new playbook if one does not already exist. The editor it will open is Vim which allows me the opportunity for shameless self-promotion … I already did a blog on learning VIM …</p><p><a href="https://medium.com/@hammad.ai/how-i-learned-tmux-became-a-workflow-ninja-7d33cc796793">How I Learned TMUX &amp; Became A Workflow Ninja</a></p><p>But you don’t have to go through all that. I’m a good guy. So I will tell you what you need to do.</p><p>When a new tome playbook is created it will open a blank file in VIM which does not have a name yet, because the file is not yet saved anywhere. You can type i to enter edit-mode and when you are done, type esc to exit edit-mode.</p><p>To save, you can use shift + :+ w + &lt;file_name&gt;. &lt;file_name&gt; is the name you want to save your playbook as.</p><p>To exit you can use shift + :+ q.</p><p>The main idea is to have a terminal editor (Vim/NeoVim) and use whatever commands written in there in any sequence you like. Here’s the official demo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/698/1*LeesGjWmTu6k0FWs_lpcuw.gif" /><figcaption>source: tome repo</figcaption></figure><h4>🟢 <a href="https://github.com/tmux-plugins/tmux-logging">tmux-logging</a></h4><p>As the name suggests, it <em>logs the activities</em> which go inside a TMUX session. This is useful because there are times where I need to retrospect on my actions in a server.</p><p>And if you are thinking that I do this because I accidentally wreak havoc on a server … then yes that is exactly why this plugin is necessary.</p><p>The thing is that I can easily see my previously run commands using the history command. In case you don’t know, this commands outputs a list of commands previously run in chronological order (last one being the latest command in history). But that does not give me the <em>exact behavior</em> of the server at that time. I don’t have any way to know if a command worked or not when I was previously working on my server.</p><p>This plugin not only stores the commands but also stores their respective outputs in a *.log file inside $HOME directory.</p><p>What’s more, it is also able to take a screenshot (textual) of your currently open terminal session. This means that everything that you can see in your terminal now gets stored in a *.log file.</p><p>It uses the prefix + shift + p to start/stop recording terminal actions and prefix + alt + p to take a screenshot of the current session. This is how the status bar at the bottom changes when you start/stop recording.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/724/1*nO0_hjdnzC1p7haLONyPOA.png" /></figure><h4>🟢 <a href="https://github.com/laktak/extrakto">Extrakto</a></h4><p>It is <em>sort of </em>a clipboard manager which can work on Windows, Mac and Linux. But there is a tmux plugin for it as well. Extrakto is also popular with Vim and NeoVim.</p><p>This plugin allows you to select text from your terminal session. It provides a search bar which fuzzy matches the text in your search query with everything else that is in your session. It uses <a href="https://github.com/junegunn/fzf">fzf</a> for fuzzy matching.</p><p>The plugin can be accessed by prefix + tab combination and looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*Z3GO2R1Y4kc36jGJJMsR-w.png" /></figure><p>As you can see, it allows several operations while the plugin popup is shown. Pretty convenient if you ask me and also good for flexing.</p><h3>Honorable Mentions</h3><p>These are just some plugins which although I haven’t used, but I think are cool to have.</p><h4>🟢 <a href="https://github.com/bjesus/muxile">muxile</a></h4><p>This plugin lets you control tmux sessions from your mobile phone. Quite handy when you are on the go and someone from your team calls you because your server crashed (or something along those lines).</p><p>It requires the person sitting on the PC/Server to start and share a TMUX session to the person using the phone. This sharing is done via a QR code, which you can scan to get access to the session. After that, you can pretty much do anything.</p><p>Here’s a <a href="https://github.com/bjesus/muxile">video preview</a> of how it works.</p><p>To be honest, I haven’t used this one too much, but no doubt it is a handy tool for emergencies.</p><h4>🟢 <a href="https://github.com/kiyoon/treemux">treemux</a></h4><p>A sidebar with the modern Nvim-Tree file explorer for the current path, with bi-directional interaction in focus. Honestly it is way better than tmux-sidebar but has a dependency on <a href="https://www.lua.org/">LUA</a> language and of course … <a href="https://neovim.io/">NeoVim</a>.</p><p>What blew my mind on this one is that you could use your mouse to resize the sidebar and access files on it the same way. If you don’t have issues with some extra dependency, then choose this one over tmux-sidebar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*1-sB4lbWkeKBTSMQKIoXyw.gif" /><figcaption>Source: treemux repository</figcaption></figure><blockquote><em>📌</em> To be honest, I haven’t used this one … yet. That is because I haven’t used NeoVim … yet. Did I turn soft? Absolutely not. I’ll not only learn how to use NeoVim, but I will also write a blog post on it too. Let me know if you would be interested.</blockquote><h3>How To Create TMUX Plugin</h3><p>TMUX Plugin Manager has a <a href="https://github.com/tmux-plugins/tpm/blob/master/docs/how_to_create_plugin.md">guide for making your own plugins</a>. To make one, you will need understanding of <a href="https://www.shellscript.sh/"><em>Shell Scripting</em></a> and <a href="https://git-scm.com/book/en/v2"><em>Git</em></a>. That’s it!</p><p>Use the links I gave you to master both, and you are all ret-2-go.</p><h3>Final Word</h3><p>Obviously I did not mention all of the plugins. And I may or may not have mentioned your favorite ones. This does not in any way mean those other plugins are useless or just not worth your time. All of them are wonderful and cover a specific usecase.</p><p>It is just that I only mentioned the ones that I frequently use <em>in my workplace, </em>and also that I haven’t used or had the need to use all of them. But just as an appreciation, let me know in the comments below if I didn’t mention a plugin which could have made my day more productive or have helped me in any other way.</p><p>As a sidenote, I’d like to motivate the junior devs out there. While researching about these plugins, I stumbled upon <a href="https://github.com/ofirgall/tmux-browser">tmux-browser</a>. While I was imersed inside the source code of this plugin I saw a typo. As much as a grammar Nazi I am, I couldn’t over look that. So I fixed that typo and submitted a Pull Request. The <a href="https://github.com/ofirgall">guy</a> (whose repo it was) was very nice and accepted the Pull Request with a thanks.</p><p>Here is what I fixed:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/956/1*KYsHum_CHRUaO0LT77oCzQ.png" /><figcaption>tmux-browser source code</figcaption></figure><p>I just hunted down a free PR 😆. Turns out you don’t have to be knowledgeable to contribute. You just need to be ready to help and review other’s work and they will appreciate that.</p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>Now with this knowledge you are able to supercharge your workstation. TMUX is a great tool and these plugins not only make it easier to use it but also adds valuable features to it that gives your regular terminal many dimensions.</p><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to listen to your feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=41a9b46f7bcb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How I Learned TMUX & Became A Workflow Ninja]]></title>
            <link>https://medium.com/@dev-in-trenches/how-i-learned-tmux-became-a-workflow-ninja-7d33cc796793?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/7d33cc796793</guid>
            <category><![CDATA[developer-tools]]></category>
            <category><![CDATA[workflow-management]]></category>
            <category><![CDATA[command-line]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[tmux]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Tue, 30 Jan 2024 13:09:00 GMT</pubDate>
            <atom:updated>2024-01-30T13:09:00.649Z</atom:updated>
            <content:encoded><![CDATA[<h4>A human friendly way to learn TMUX</h4><p>Since you took the time to click this article, I would assume that you too, want to prove that your terminal skills are par excellence.</p><p>This is a breakdown of how I learned <a href="https://github.com/tmux/tmux/wiki">TMUX</a> without getting tangled into the plethora of features it offers, and how I mastered it bit by bit.</p><p>If you have read my previous article where I explain <a href="https://medium.com/@hammad.ai/how-i-learned-vim-and-flexed-in-front-of-other-developers-fb2a1051f814">How I Learned VIM Flexed In Front Of Other Developers</a>, you would already know what to expect from this one.</p><p>I will walk you through what to learn first and what should come after, step by step. We will uncover the power that TMUX offers gradually as we slowly, but surely, become a <em>terminal ninja</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/601/1*-rMNuwYtuj-48e_hesml7g.png" /><figcaption>A ninja who have mastered the arts of navigating through multiple terminal panes and session management. Beware those who challenge this honed assassin to a command-line showdown.</figcaption></figure><h4>TL;DR</h4><p>Many a time I have had the need to open up more than one terminal session in my server machine which is located in the cloud. I usually connect to my server using <a href="https://en.wikipedia.org/wiki/Secure_Shell">SSH</a> connection and that allows me to connect to my server while staying within my current terminal on my machine.</p><p>I could however open up another SSH connection on another terminal, but that would not be feasible where the server’s <em>price plan</em> is concerned. Those who have had the pleasure of working with a server, would sympathize with me.</p><p>Another problem I faced was the internet connectivity. If the connection strength fluctuated, the SSH connection would drop dead, and my processes will get affected, leaving me no choice but to wait for a stronger signal and try again next time.</p><p>When I heard TMUX can solve these problems and provide more value in my day-to-day tasks as a software developer, I said, “<em>Let’s jump right into it!</em>” without having a second thought. But I soon found out the overwhelming amount of features it has and the shortcuts which come with those features.</p><p>Simply memorizing the shortcuts is not my style, since I am a busy guy with a day job. Memorizing is a waste of time without any productive long term gains, and time is something I don’t normally have the privilege of spending like this. Instead, I like to merge the <em>learning </em>part into my daily chores.</p><p><strong>What I am NOT doing here …</strong></p><ul><li>I’m not going to cover all the shortcuts or shenanigans TMUX has to offer. I will <em>deliberately</em> skip some stuff. But you can rest assured that we will cover those things which will enable us developers to do what we do but better.</li><li>I’m not going to explain the basics like what is TMUX and the theory and history behind it. This is not the place where you will that kind of <em>blog-expanding</em> material.</li></ul><p>So without further jib jab, let’s start with this regime.</p><h3>A Few Words About Practicing TMUX</h3><blockquote><strong>Disclaimer:</strong> If you can already use TMUX then skip this section without delay. If not or if you are curious, then please, by all means, read on.</blockquote><p>I understand that not all of you will have a Linux system like I have. TMUX does not run on Windows OS, nor does any online code execution platform e.g. Github Codespace, Replit or Gitpod supports TMUX. So you might wonder if there is an alternative or not.</p><p>There are several:</p><p>👉 <strong>Alternative 1:</strong></p><p>Use <a href="https://tryhackme.com/room/rptmux">TryHackMe TMUX Lab</a> to practice what you learn here. They give you a virtual machine in your browser with GUI support, so that you will feel right at home. Since it is a lab it comes with a tutorial too.</p><blockquote><strong>The Catch</strong>: But there is a <em>time limit</em> of how long you are able to use it.</blockquote><p>👉 <strong>Alternative 2:</strong></p><p>Use <a href="https://www.virtualbox.org/">Virtual Box</a> to set up a Linux OS and install TMUX inside it. You will have to learn how to set it up on your own. You won’t be relying on anyone, and you will still get a GUI interface.</p><blockquote><strong>The Catch</strong>: It uses system resources, so if you don’t have much RAM or storage, you may still use it but with heavy lags.</blockquote><p>👉 <strong>Alternative 3:</strong></p><p>If you are on Windows OS, you can install WSL which stands for <a href="https://wiki.ubuntu.com/WSL"><strong>W</strong>indows <strong>S</strong>ubsystem for <strong>L</strong>inux</a>. It will let you use Linux commands via Windows Command Line. Neat huh?</p><blockquote><strong>The Catch</strong>: It can prove to be difficult to set up if you are a beginner. Things might go over your head even if you had a <a href="https://learn.microsoft.com/en-us/windows/wsl/install">step-by-step guide</a>.</blockquote><p>👉 <strong>Alternative 4:</strong></p><p>This is my favorite, as it does not rely on a third party and consumes my systems resources more efficiently than VirtualBox.</p><p>Since we only need a terminal where we can practice without a GUI part, we will set up a Linux environment inside a Docker container and access it.</p><p>Use the following commands to set it up:</p><pre># download and run an Nginx OS<br>docker run -t -d  -p 80:80 nginx:latest /bin/bash<br><br># list out all the containers and find your container-id<br>docker ls<br><br># start a bash terminal inside the container (replace the &lt;container-id&gt;)<br>docker exec -it &lt;container-id&gt; /bin/bash</pre><p>You’ll know you have succeeded when you see something like root@12345678:/ #.</p><blockquote><strong>The Catch</strong>: You need your PC to be able to support <a href="https://en.wikipedia.org/wiki/Hardware_virtualization">hardware virtualization</a> and run Docker. Even if your system does not support it, you can start this docker container in Github Codespaces and then use TMUX there.</blockquote><p>If any of you have any other bright ideas … I’m all ears! Tell me in the comments. 👇</p><h3>Day 1: Shoot &amp; Scoot</h3><p>If you know me any better, I always start with a<em> shoot and scoot</em> scenario which is concise, focused and practically doable. In this scenario, I think of some very <em>minute </em>tasks that I want to do with a tool. In this case, it is TMUX.</p><p>Since my daily chores involves opening and closing SSH sessions across different server, a very simple procedure of starting and closing of a TMUX session would do just fine.</p><p>So here are the steps I followed in my shoot &amp; scoot approach (<em>The simple approach</em>):</p><ul><li>Open session</li><li>Do something useful like running a deployment shell script in the server (<em>it’s ok if you don’t get this part. Sometimes I don’t get it either</em>).</li><li>Close the session</li></ul><p>But doing this for a single session would be very similar to what I have been doing up till now <em>without </em>using TMUX at all. Also, I would not be leveraging any of the <em>benefits </em>of TMUX if I followed this approach. Therefore, I was tempted to make things a little difficult by being able to start and close <em>multiple</em> sessions instead of just one.</p><p>You may want to do it just like I did in <em>The spiced up version </em>or if you do not feel comfortable in the terminal, just stick to the <em>The simple approach</em>.</p><p>Changing things in my previous approach a bit (<em>The spiced up version</em>) it should go in a somewhat similar fashion to this:</p><ul><li>Start a TMUX session (session A)</li><li>Start another TMUX session (session B)</li><li>Do something useful in session A.</li><li>Switch over to session B.</li><li>Do something useful in session B.</li><li>Close the TMUX session A.</li><li>Close the TMUX session B.</li></ul><p>In this way, I am able to open and close multiple sessions (being more productive) while still keeping the whole procedure to a minimum.</p><p>Here are the commands I practiced in Day 1:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/621/1*yU969M0Ct31Kk1Ia0iBQOA.png" /></figure><p>So what is session-id you ask? well, at the bottom-left corner, after you start a TMUX session, you will see something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/393/1*thiOUlHUzV__lU91JpKBNA.png" /><figcaption>session id of a TMUX session (bottom-left corner)</figcaption></figure><p>The [0] represents the session number among a list of sessions. Here, it is zero, which means the very first session. Both the zeroes you see above have different meaning, which you will learn about soon.</p><p>TMUX sessions have three states: Active, Dormant and Exited. These words are just my own invention, by the way.</p><ul><li><strong>Active </strong>👉 the session is currently opened, and you are able to use it.</li><li><strong>Dormant </strong>👉 the session is running in the background, ready to be reused.</li><li><strong>Exited </strong>👉 the session is not running or have ceased to exist.</li></ul><p>When you write tmux or tmux new in the terminal, you are essentially creating a new session and making it <em>active</em>.</p><p>Similarly, when you delete a session using tmux kill-ses, you are exiting either an <em>active</em> or a <em>dormant</em> session.</p><p>You can use tmux kill-ses from within or outside of a session. When used outside all sessions, it deletes the most recently created one, regardless of its state.</p><p>But when you detach from a session using tmux detach or using the keyboard shortcut CTRL+b ... d, you are changing the state of the TMUX session from <em>active</em> to <em>dormant</em>. Or in the case of attaching back to (resume) a session, the state goes from <em>dormant</em> to <em>active</em>.</p><p>I hope that makes sense. If not, read again. 😅</p><blockquote><em>📌</em> Now there were cases where I have to go out of my way to look at those commands or shortcuts which I had not planned for in a certain day. For that reason, I used CTRL+b ... ? to view all shortcuts. It’s obviously very helpful.</blockquote><h3>Day 2: Mastering Panes</h3><p>There are two ways you can manage multiple sessions at once. One way includes using Panes, and the other is by using Windows.</p><p>I chose to go with Panes as they are easier to manage. The reason for this, as I think, is that seeing multiples panes in your terminal screen gives you a sense of what is happening simultaneously. An example of multiple pane view is given below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1006/1*wU0CiUBT7GhU9fAXD7jgPA.png" /><figcaption>Example view of multiple panes in one single terminal session.</figcaption></figure><p>Any ways, you may decide to go with either as you prefer.</p><p>The commands I planned to practice in Day 2 are as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/626/1*lrLKg0E701HCE-zEulRQEg.png" /></figure><blockquote><em>📌</em> You will be using <em>CTRL+b</em> (prefix command) a lot. It is kind of a specific command only for TMUX. To use it, you will need to press both <em>CTRL</em> and <em>b</em> simultaneously, and release them before pressing any more buttons. This “release action” is shown as <em>...</em> in the above and upcoming commands.</blockquote><p>Now there are three categories of commands here, so let&#39;s go over them one by one.</p><p>To manage panes, you will obviously need a way to create new panes and delete them at will. That is where the <strong>General Pane Operations</strong> come in.</p><p>Creating a new pane comes with an option. The new pane you are trying to create will split up your terminal into sections. Now, you may choose if you want to split those sections vertically (by pressing %) or horizontally (by pressing &quot;).</p><blockquote><em>📌</em> Note that &quot; on keyboard can only be accessed in combination with a SHIFT key. So, &quot; is actually typed on a keyboard as SHIFT+&#39; (shift and apostrophe keys). Same goes for % and any other symbol which is accessed with a SHIFT key.</blockquote><p>The kill pane command only deletes the pane which is currently <em>active</em>, and you are automatically switched over to another <em>dormant</em> pane.</p><blockquote><em>📌 </em>Yes, panes have states too. But you are able to see all of them at once, unlike sessions.</blockquote><p>While using panes for the first time, I had this urgent need to arrange them such that it is easier to <em>visualize</em> them. Therefore, I added <strong>layout commands</strong> to the list. CTRL+b ... SPACE allows me to switch between multiple pane arrangements.</p><p>CTRL+b ... ALT+&lt;1..5&gt; similarly switches between layout but lets you directly select which layout you want. There are a total of 5 options.</p><p>CTRL+b ... z allows me to toggle between full-screen state of a single pane. Think of it like a “full-screen” or “maximize window” button.</p><p>This was a bit extra but pretty useful.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hwFlu42utTojue-5ZR0ArQ.png" /><figcaption>Second Pane shown as full-screen (Ctrl+b … z)</figcaption></figure><p>Lastly, to navigate between panes you use <em>arrow keys</em> but only after using the CTRL+b combo.</p><blockquote>📌 I deliberately skipped the CTRL+b ... ! command which allows me to convert a pane into a window. This was very similar to CTRL+b ... z combo I just showed you.</blockquote><h3>Day 3: Managing Windows</h3><p>Panes are good, but having too many will soon start to clutter the terminal real-estate. That is where windows come in.</p><p>Window acts in a similar way to a Pane, but the major difference is that instead of dividing a terminal screen into sections, it takes all the available terminal space to display itself (like a full-screen pane).</p><p>If you are still confused, here is a comparative analysis of Windows and Panes to clear out any doubts:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/801/1*vJAq-ovg3DRpktSdFVsLJw.png" /><figcaption>Comparative analysis of Windows and Panes in TMUX.</figcaption></figure><p>Here are the commands I practiced in Day 3:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/626/1*rVuHPuC9Pl0nswYgoeLm8w.png" /></figure><p>CTRL+b ... c is used to spawn a brand-new window. To close a window, you will use CTRL+b ... &amp;.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/527/1*VIegr4vHZundqFuKYzV7_w.png" /><figcaption>multiple windows with name “bash”</figcaption></figure><blockquote>📌 Notice the - symbol after the 3:bash. That - represents the previous window you were at before switching to the current window. If you press CTRL+b ... l you will jump to the window marked by -. But hey! spoiler alert … this command is to be discussed in Day 5.</blockquote><p>Just like how you used <em>arrow keys</em> with CTRL+b combo, you can use p or n to navigate between windows. But after navigating through windows like this for a while, I thought if there is a better way to do it … Yup there is and you’ll love it.</p><p>CTRL+b ... w not only shows you how many windows are there but also displays information about each window like how many panes are active inside it.</p><p>That’s not even the best part. It is not actually a list, it’s a <em>menu </em>which you can navigate with all four arrow keys and select a window/pane you want to go to by pressing ENTER.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*VHPWz6XA45VC8eYTCHCUzw.png" /><figcaption>Example of window menu. Open it by pressing CTRL+b … w</figcaption></figure><p>In this mode you can also use CTRL+b ... x while highlighting a pane or a session to delete it.</p><blockquote><em>📌</em> Notice the - sign after some arrows <em>➡️</em>? that shows an expanded tree. Use left/right arrow keys here to toggle this hierarchy tree.</blockquote><h3>Day 4: Advanced Session Commands</h3><p>Using TMUX over and over, having multiple sessions at my disposal and all of them running something important, I had a need to identify those session with something other than the index they are assigned.</p><p>Since there are commands which allow me to manipulate sessions based on their <em>names</em> instead of their <em>index numbers</em>, I thought it would make my life even easier.</p><p>It should be noted that by this time I was already <em>over-equipped</em> to use TMUX and I was already leveraging it to my benefits.</p><p>The commands I practiced on Day 4 are as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/616/1*I7yNkRLAiJWjJYcs7kO2IQ.png" /></figure><p>The a flag can be interchangeably used with attach. The <strong>session-name</strong> is the same as <strong>session-id</strong>.</p><p>Not going to explain much about it because it is self-explanatory. Also these commands were repetitive and I was able to easily remember them, therefore I decided to cover some more.</p><p>These quick peek commands displays a list of windows, panes or sessions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/635/1*b1AhfiN298Kb_3P7MVgQXA.png" /></figure><p>This day would seem lazy if you are eager to learn more. But I planned it out to have a <em>pause-and-reflect</em> moment. We have covered so much ground, it is only natural that we stop and ponder on what we have learned and also make sure we haven’t forgotten anything along the way.</p><h3>Day 5: Streamlined Shortcuts</h3><p>I dedicated this day for <em>make-life-easier</em> shortcuts.</p><p>By this time I was already pulling stunts in front of my co-workers and what I had learned up till now was more than sufficient for my daily tasks.</p><p>At this point you have a choice: either continue learning more or stop and focus on something else entirely. Me being me, chose the former. If I was going to have an everlasting effect on my co-workers by pulling terminal stunts, I had to make sure I’m not falling behind on anything.</p><p>Yes, my reasoning is based on 80% showoff and 20% for work efficiency. Why else would I do it? 😅</p><p>Anyways, the commands I practiced this day were about session, pane and window management. Wait more shortcuts? Yes, I certainly wasn’t lying when I said I was overwhelmed by its features.</p><p>For panes I have the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/635/1*KB7kOmvIKpc26eQcyd-q7g.png" /></figure><p>Where CTRL+b ... q shows index of each pane. It would look something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1003/1*NuURPhF4vdEjsnCPIu-LGQ.png" /><figcaption>Highlighted pane indices (Ctrl+b … q)</figcaption></figure><p>Meanwhile, CTRL+b ... q &lt;pane-index&gt; will let you jump to the pane index you specify. I mostly used both the variants of this command simultaneously. It is a good exercise.</p><p>I soon realized that I did not often use CTRL+b ... ! to convert a pane into a window. I already had the ability to toggle a pane to full-screen (Day 2). So you may decide to ignore this one.</p><p>CTRL+b ... { / } swaps the current pane with the adjacent pane. You will get it when you do it yourself.</p><p>Now for the session shortcuts, here they are:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/635/1*LfCtteaEUsfU00r9NfsU5Q.png" /></figure><p>CTRL+b ... s is very similar to CTRL+b ... w which we already practiced (Day 3).</p><p>I already knew the command to create a <em>named </em>session (Day 4), but I may need to <em>rename</em> an already created session to something else. Therefore I used CTRL+b ... $.</p><p>Moving onto the window shortcuts:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*vE7LkQdwQAHdPPHxPgUYuA.png" /></figure><p>This was pretty useful compared to other shortcuts we discussed in this day.</p><p>CTRL+b ... f will prompt you to find a window by its name and when you hit enter you will see a menu of results. Then you may pick a window from there.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1004/1*aCj0srHLMLPpewWLyL6QLQ.png" /><figcaption>Multiple windows with custom names assigned to them. Asterisk(*) represents the current window.</figcaption></figure><p>CTRL+b ... l works like a “back” button to visit the last window we were working on.</p><h3>Day 6: Copy Mode</h3><p>This is purely optional. You may decide to skip this entirely and move onto the next day.</p><p>I was already using a tool in Ubuntu called <a href="https://launchpad.net/diodon">Diodon</a>. It is a clipboard manager which let’s me keep a history of my clipboard and reuse anything that is in it. This requires a few clicks so I was already fine with it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*wu2CshsPdwMbdbL0HVaNTw.png" /></figure><p>Please note that these commands may or may not work for you based on your shell configurations. To troubleshoot the issue (if you find any) you can find a <a href="https://stackoverflow.com/questions/18683252/tmux-copy-does-not-work">solution here on Stackoverflow</a>.</p><p>This trouble-shooting guide I just showed you may require you to edit the .tmux.conf file located in your $HOME directory. I will not be covering that here.</p><h3>Day 7: Command Mode</h3><p>This is the last and most useful (and advanced) usage you can get out of TMUX.</p><p>Command mode, as it sounds like, lets you pass commands which can manipulate how your version of TMUX works. Of course it can be used to customize your shortcuts and stuff. You can even get rid of the CTRL+b combo and use some other (feasible) combination of keys in its place.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*8qzTnl1F3NClGvmrDCi9xw.png" /></figure><p>I will only be covering some commands here of course, since covering them all will make this article even longer and<em> we don’t want that … do we?</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*CoVBTiau0SrI4SBjTg9aJQ.png" /></figure><p>In case you are wondering, the flags used above represent the rectangular side of each pane which you want to resize. Pretty dumb huh? Let’s see something more useful.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*lTDnsdflE_Kt1GafFsgcrw.png" /></figure><p>These commands are used for changing the settings of the session or the window. You can add a -g flag to have your setting take effect on a <em>global</em> level. Here are some examples which you may like:</p><p>set commands:</p><ul><li>set prefix C-a: Changes the default prefix key to Ctrl+a (instead of Ctrl+b).</li><li>set status-bg black: Sets the background color of the status bar to black.</li><li>set mouse on: Enables mouse support for scrolling and selecting text.</li><li>set history-limit 10000: Increases the scrollback buffer size to 10000 lines.</li></ul><p>setw commands:</p><ul><li>setw mode-keys vi: Sets the copy mode key bindings to vi-style.</li><li>setw pane-base-index 1: Numbers panes starting from 1 instead of 0.</li><li>setw window-status-current-style fg=yellow: Highlights the current window&#39;s status line in yellow.</li><li>setw automatic-rename on: Automatically renames windows based on the active process.</li></ul><h3>Good To know</h3><ul><li>TMUX can be configured using using it’s <a href="https://github.com/tmux/tmux/wiki/Getting-Started#configuring-tmux">config file</a> which is usually present in $HOME directory. The file itself is named as .tmux.conf. Here you can do all sorts of <em>customization</em> like changing the CTRL+b combo to something else.</li><li>To use the .tmux.conf file, you can use the command tmux source /path/to/.tmux.conf.</li></ul><h3>Final Word</h3><p>This concluded my 7-day sprint of practicing TMUX. Of course, there are lots of other commands which I haven’t covered yet. And I didn’t plan on doing so in one go.</p><p>After a week of TMUX training, I can handle most daily tasks without keeping a cheat sheet hostage. The keyboard fluency feels like ninja-level and my workflows are now smooth. Still there are mountains of commands to conquer, but that’s another sprint!</p><p>Do you realize now what’s next? Customize your own TMUX config. That would not only show others that you know what you are doing, but also allow you to explore a bit more on how TMUX works.</p><p>TMUX is a nice tool to have in your developer’s <em>utility belt</em>. Learning to use it can be difficult. As with anything else, becoming a proficient user of it requires time.</p><p>Nonetheless, learning to show off makes you learn it in a more serious way, <em>doesn’t it?</em></p><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>Now you are ready to pull some serious stunts in front of other developers. Show them how you CTRL your terminal … 😏</p><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know your thoughts 📣on it. I’d love to listen to your feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7d33cc796793" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Create An Invoice Generator Using Python, Jinja2 & Weasyprint]]></title>
            <link>https://medium.com/@dev-in-trenches/create-an-invoice-generator-using-python-jinja2-weasyprint-48ef1f450ac5?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/48ef1f450ac5</guid>
            <category><![CDATA[html]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[factory-pattern]]></category>
            <category><![CDATA[projects]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Sat, 16 Dec 2023 12:54:25 GMT</pubDate>
            <atom:updated>2023-12-16T16:38:29.022Z</atom:updated>
            <content:encoded><![CDATA[<p>Whenever a client asks you to do a minor task as a freelance project, what do you do?</p><p>You whip up an invoice which lists the tasks you are going to do for the client and the charges that are associated with each task. This shows that you are meticulous about detailing the scope of work and transparent about the corresponding costs. It also demonstrates your commitment to clarity and fairness in your business dealings.</p><p>Although there are many other factors which contribute to your <em>professionalism</em> when dealing with freelance clients, but this was a tool which I wanted to use instead of the robust complete invoicing solutions which overload you with features you don’t really care about.</p><p>I wanted a quick and easy solution to this, therefore I made this script, and I’m going to show you exactly how I did that.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-PqEQRD9o4k2FYwq" /><figcaption>Photo by <a href="https://unsplash.com/@susangold?utm_source=medium&amp;utm_medium=referral">Susan Gold</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>The Landscape</h3><p>I wanted to keep it simple … stupid simple. So instead of going for an OOP approach as I usually do, I went and made a function. But to make it somewhat customizable I added a settings.py which contains configurations on how you want to set your invoice up.</p><p>The invoice itself is an HTML file which is written in jinja2 syntax. The data that is rendered into this template comes from data.json.</p><p>Naturally I went for a primitive <strong>factory design pattern</strong> which uses render_template() as a factory which is inside invoice_gen.py.</p><p>Here is what each file is meant for:</p><ul><li>data.json 👉 contains data to be rendered into Jinja template.</li><li>invoice_gen.py 👉 the script file, which serves as a factory to generating invoices.</li><li>settings.py 👉 contains configuration for the HTML template.</li></ul><blockquote><em>📌</em> The naming convention I have used here is inspired from Django such as settings.py, get_context_data() etc</blockquote><p>Just so you can understand better, I have illustrated how it works in the diagram below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2aPlqHx8h6ASBNbG7eb_Vg.png" /></figure><h3>Technologies</h3><p>We are using the following:</p><ul><li><a href="https://jinja.palletsprojects.com/en/3.1.x/">Jinja</a></li><li><a href="https://weasyprint.org/">WeasyPrint</a></li></ul><h3>The Data File</h3><p>This is just a json file which contains all the information we want to render in our template. Mine looks something like this:</p><pre>{<br>    &quot;title&quot;: &quot;Services Invoice&quot;,<br>    &quot;invoiceNumber&quot;: 13,<br>    &quot;issueDate&quot;: &quot;11-12-2023&quot;,<br>    &quot;dueDate&quot;: &quot;18-12-2023&quot;,<br>    &quot;status&quot;: &quot;due&quot;,<br><br>...<br><br>    &quot;server&quot;: {<br>        &quot;logo&quot;: &quot;path/to/logo.png&quot;,<br>        &quot;companyName&quot;: &quot;Hammad&#39;s Company&quot;,<br>        &quot;firstName&quot;: &quot;M. Hammad&quot;,<br>        &quot;lastName&quot;: &quot;Hassan&quot;,<br>        &quot;address&quot;: {<br>            &quot;city&quot;: &quot;Karachi, Sindh&quot;,<br>            &quot;country&quot;: &quot;Pakistan&quot;<br>        },<br>        &quot;email&quot;: &quot;hammad.hassan@localhost.com&quot;,<br>        &quot;profileURL&quot;: {<br>            &quot;url&quot;: &quot;https://www.upwork.com/freelancers/~01f9b5bc6f481f0385&quot;,<br>            &quot;displayText&quot;: &quot;Hammad on Upwork&quot;<br>        }<br>    },<br>    &quot;itemList&quot;: [<br>        {<br>            &quot;title&quot;: &quot;Python Course&quot;,<br>            &quot;description&quot;: &quot;Python basics course to get you started&quot;,<br>            &quot;isFixedPrice&quot;: false,<br>            &quot;rate&quot;: 10,<br>            &quot;hours&quot;: 15<br>        },<br>        {<br>            &quot;title&quot;: &quot;HTML/CSS/JS&quot;,<br>            &quot;description&quot;: &quot;Beginner&#39;s frontend course&quot;,<br>            &quot;isFixedPrice&quot;: false,<br>            &quot;rate&quot;: 6,<br>            &quot;hours&quot;: 10<br>        }<br>    ],<br>    &quot;moderatorCharges&quot;: 0.1,<br>    &quot;percentIncreaseAfterDueDate&quot;: 0.05<br><br>...<br><br>}</pre><p>The above JSON file is a shortened version of the real one I’m using.</p><blockquote>📌 In case you have read the above data and have questions …</blockquote><blockquote>Yes, I do teach programming on an individual basis to all kinds of students. Those who don’t have a computer science background are more than welcome to have a chat.</blockquote><h3>The Main Script</h3><p>The process of generating invoices from a set of data defined in data.json uses several resources in order to spit out an invoice you can send to your clients.</p><p>First, you will need to import your dependencies.</p><pre>from jinja2 import Template<br>import json</pre><p>Then we write the function which inserts some <em>contexts</em> into a Jinja HTML template and will later convert those templates to pdf.</p><pre>def render_template(<br>    template_file:str, <br>    context:dict, <br>    styles:list, <br>    output_filename:str<br>)-&gt;str:<br>    <br>    # get the template file and render it using context variables<br>    template = Template(template_file)<br>    rendered_html = template.render(context)<br><br>    # set names for output files<br>    html_file = f&quot;{output_filename}.html&quot;<br>    pdf_file = f&quot;{output_filename}.pdf&quot;<br><br>    # writing html content to a file<br>    with open(html_file, &#39;w&#39;) as file:<br>        file.write(rendered_html)<br><br>    # Convert HTML to PDF using WeasyPrint<br>    HTML(html_file).write_pdf(pdf_file, stylesheets=styles)<br><br>    # return the name od the file<br>    return pdf_file</pre><p>And now within the same script file we will load the assets we need in order to render our template.</p><pre># Load context data<br>context_data = {}<br>with open(&quot;./data.json&quot;) as data:<br>    context_data = get_context_data(json.load(data))<br>    <br># load Jinja template<br>template_html = &quot;&quot;<br>with open(TEMPLATE_HTML_PATH) as template:<br>    template_html = template.read()<br><br># Render the template and generate the PDF<br>pdf_filename = render_template(template_html, context_data, TEMPLATE_CSS, OUTPUT_FILENAME)<br>print(f&quot;PDF generated: {pdf_filename}&quot;)</pre><p>We are loading context data from the get_context_data() function, which is located in settings.py. This function accepts only one parameter, that is a python dictionary. We get this dictionary from data.json.</p><blockquote><em>📌</em> Keep this in mind as it will become relevant soon.</blockquote><p>We also load a Jinja template (which is just an HTML file) and read its contents using the with keyword and open function. TEMPLATE_HTML_PATH comes from settings.py which is explained in the next section.</p><p>Lastly, we call our function render_template() to do its magic.</p><h3>The Settings File</h3><p>This file contains all the customizable parts of the script. So if you want to change the outcome of the above-mentioned script, you only need to make changes to this file.</p><p>Import your dependencies, which now include weasyprint.</p><pre>from weasyprint import HTML, CSS<br>from datetime import datetime</pre><p>This file only contains three variables and a function.</p><pre>OUTPUT_FILENAME = f&quot;output-{datetime.now().strftime(&#39;%d-%b-%Y&#39;)}&quot;<br>TEMPLATE_HTML_PATH = &quot;./invoice_template_002.html&quot;<br><br>TEMPLATE_CSS = [<br>    CSS(&quot;./invoice_template_002.css&quot;),<br>    CSS(&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css&quot; ),<br>    CSS(&quot;https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css&quot; )<br>]</pre><p>The first two variables are self-explanatory, so I’m not going to waste time on those.</p><p>TEMPLATE_CSS however, is a list of CSS objects which are imported from weasyprint library.</p><p>In this list you can add as many CSS modules as you like and all of them will be applied to your HTML template.</p><p>The first element in this list is my own custom CSS, therefore it has a relative path. The other two are links from <a href="https://getbootstrap.com/">Bootstrap</a> and <a href="https://fontawesome.com/">Font Awesome</a> CDNs.</p><pre>def get_context_data(context_json:dict)-&gt;dict:<br>    &quot;&quot;&quot;This function manipulates the context you import from data.json&quot;&quot;&quot;<br>    context_json[&#39;issueDate&#39;] = datetime.strptime(context_json[&#39;issueDate&#39;], &#39;%d-%m-%Y&#39;).strftime(&#39;%d-%m-%Y&#39;)<br>    context_json[&#39;dueDate&#39;] = datetime.strptime(context_json[&#39;dueDate&#39;], &#39;%d-%m-%Y&#39;).strftime(&#39;%d-%m-%Y&#39;)<br>    context_json[&#39;invoiceDate&#39;] = datetime.strptime(context_json[&#39;issueDate&#39;], &#39;%d-%m-%Y&#39;).strftime(&#39;%B&#39;)<br>    return context_json</pre><p>get_context_data() does exactly what it says. It fetches the context data, allows users to manipulate that data like applying formula and performing calculations and returns the data as a python dictionary.</p><p>I used this function because although data.json has a lot of information, I did not put in data which should be calculated. For example, you have different products you are selling in your invoice, but the <strong>total amount</strong> you are charging the customer should be <em>calculated </em>rather than<em> hard coded</em>.</p><p>But you don’t see me calculating any of that in the function above. That is because I chose to perform the calculations <strong>inside the Jinja template</strong>.</p><p>In either case, I am not <em>hard coding</em> numbers here and there.</p><p>I’m not going to include the template file here, as it is very long and will cover too much space. But you can check out my GitHub repo for complete code.</p><h3>GitHub Repo</h3><p><a href="https://github.com/Blankscreen-exe/invoice_generator/tree/main">GitHub - Blankscreen-exe/invoice_generator: python invoice generator using Jinja2 and WeasyPrint</a></p><h3>Sample Preview</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/990/1*R6Lqb9ZyzbunrevCGHf5uQ.png" /></figure><blockquote><em>📌</em> I found the original HTML template <a href="https://www.bootdey.com/snippets/view/bs4-invoice">here</a>, and modified it to fit my needs.</blockquote><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>Above is just one possibility of what you can do with the factory code I provided. As an example, you can also make certificates, style them with CSS and put the name of the recipient in data.json.</p><p>I hope you will have fun using it.</p><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know 📣 your thoughts on it. I’d love to listen to your feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=48ef1f450ac5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Will Learning AI Make Me Future Proof? (Answered With Different Perspectives)]]></title>
            <link>https://medium.com/@dev-in-trenches/will-learning-ai-make-me-future-proof-answered-with-different-perspectives-d8e45d1b51f8?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/d8e45d1b51f8</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[future-of-work]]></category>
            <category><![CDATA[bard-ai]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Sun, 10 Dec 2023 09:33:33 GMT</pubDate>
            <atom:updated>2023-12-19T14:54:21.363Z</atom:updated>
            <content:encoded><![CDATA[<h4>For People With Different Backgrounds</h4><p>This is something many young and professional experts of their fields have been asking me recently. This article is my compilation of all the answers I gave them to satisfy their questions, as well as their follow-up questions.</p><p>I’m writing this in hopes that someone may benefit from this and gain valuable insights about their future that they are planning for themselves.</p><p>Since this question is highly <strong>subjective</strong>, I’m going to answer this question for <em>Three </em>different individuals with the following characteristics:</p><ul><li>Young individuals who lack market exposure or experience.</li><li>Skilled individuals with experience in IT field.</li><li>Individuals with experience in fields other than IT.</li></ul><p>Moreover, I will also be explaining what you can do to make yourself future-proof.</p><blockquote><em>📌</em> You may want to skip to the section which best describes you, but you may also gain some deeper insights if you read the other sections as well.</blockquote><blockquote>Also, section 1 is a mandatory read.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UiuIybzcKeh-IBXn8R4wkg.jpeg" /><figcaption>Image of the revolutionary Comodore64 Personal Computer, A glimpse of the future as seen by people in 1982.</figcaption></figure><h4>TL;DR</h4><p>One thing that is common for all my answers (which is also backed by facts):</p><blockquote>“Learning AI” alone cannot make you future-proof. In fact, nothing you do has the potential to make you future-proof. No one knows the future, we can only attempt to predict it and prepare for it.</blockquote><p>With that said, learning AI will not necessarily make you future-proof BUT there are skills which can help you adapt to the future whether it is AI, decentralization or even negotiations. Those skills are your soft skills, and they are much more valuable in the long run as compared to AI.</p><p>To be honest, AI isn’t a skill, it is currently being widely accepted as the knowledge or understanding of the potentials and limits of software applications which make use of AI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZQtdVVwAlQg1Tac3mEO_w.png" /></figure><h3>1- What Does “Learning AI” Actually Mean?</h3><p>This term is <em>abstract </em>and can be taken with mixed meanings. Some of the people I talked to, were not able to pin point what it meant so here I am explaining it.</p><blockquote><em>📌</em> This section is important, and is referred in several places within this blog.</blockquote><p>There are currently, two ways to interpret this:</p><h4>1.1- Become Familiar With AI Services</h4><p>One way is to learn how to use the AI services provided by different organizations and startups, just like you would use Microsoft Windows OS , which is provided by Microsoft or Google Search Engine, which is provided by Google.</p><p>These services are provided by some organizations that enables you to create or use AI technology in exchange for some fee. There are lots of examples out there which cover a variety of different niche applications of AI, such as video editing, photo editing, image generation, chatbots etc.</p><p>The problem today is that AI is advertised as an easy source of <em>passive income</em> if you learn how to use it. So, is it wrong to believe in it? Not as long as there’s a service provider handling all the strings for you, leaving you to only select some preferences or options for how you want to run their AI service.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/552/1*QaVtvAtfQdoq3BR-tnS9FQ.png" /></figure><p>This service provider may come in various shapes and sizes. For example, Midjourney provides you with image generating services. With it, you will be able to generate images, but they hold the reins to their technology, and in this scenario, you are just a <em>user</em>.</p><p>It is a given in software development that every software products you will see out there in the market will be made with <em>user-friendliness</em> in mind. All you need to do is to get familiar with the tool, and then you will be using it to create stuff or use that service.</p><h4>1.2- Learn The Technologies Behind AI</h4><p>This path is for those who wish to dedicate themselves to the knowledge of Computer Science and Software Engineering. For non-programmers, this may be a difficult path to pursue but note that it is not impossible.</p><p>If this wasn’t clear enough, you will have to start learning the <em>techy stuff</em> like programming and application development. Yes, it is a tough route and not for the those with less patience, but then you will be learning AI <em>in a truer sense</em>.</p><blockquote><em>📌</em> I am planning to write about how should you approach learning computer science or other related/specialized subjects such as machine learning in a separate blog and add the link to it right here.</blockquote><p>There are roadmaps all around the internet which tell you step by step what you need to learn in order to be able to develop applications with AI technology. But the one I find the most intuitive and beginner-friendly with several necessary details is this one:</p><p><a href="https://i.am.ai/roadmap/#disclaimer">AI Roadmap</a></p><p>Keep in mind that going <em>in-depth</em> and learning the technical aspects such as programming is not necessary for you to learn how to use AI (as I have already shared in the section 1.1).</p><p>Moreover, the roadmap I shared with you does not incorporate any software development expertise, which is often listed with the<strong> job description</strong> of a machine learning engineer.</p><p>The reason I called this route a “tough one” is because it requires more than what is shown in the roadmap I shared above. It requires you to be a Software Engineer first, and then you will dive into the technical aspects of Machine Learning and AI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*bxFd_5LbAkGiuyUWWvydxQ.png" /><figcaption>An Enthusiast Learner trying to skip all the basic knowledge in order to dive directly into his doom.</figcaption></figure><p>The reason for this is that companies typically hire people who have a combo of Machine Learning understanding and some prior software development experience. If you only have skills in the former domain, then it is unlikely (but not impossible) for you to get hired as a Machine Learning Engineer. This is due to the fact that Machine Learning Engineers are often tasked with creating optimized <strong>end-to-end solutions</strong> and not just Jupyter Notebooks of their experiments.</p><blockquote><em>📌</em> But enough of that. I’ll be explaining about getting hired as a Machine Learning Engineer or even as an AI Specialist in a separate blog. Be sure to check that out if you are interested.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZQtdVVwAlQg1Tac3mEO_w.png" /></figure><p>Now, lets answer some questions …</p><h3>2- Young Individuals Who Lack Market Exposure Or Experience</h3><p>Not having a CS background and not having the know-how of computer basics are two different things. The answer in this section is for those who fall under both the categories. But I’ll be assuming that these are the people who have yet to dive into the professional world and get market exposure.</p><p>You may or may not have an affinity for technologies, but just being able to operate regular computer devices doesn’t necessarily make you tech-savvy.</p><p>Most people use smartwatches, but they have no idea what’s going on in there or how it does what it does. And they should not bother themselves with such things, because those devices are made with <em>user-friendliness</em> in mind. That is to say, they have yet to taste what dealing with technology is really like.</p><p>So, will it make you future-proof? Well, the reason I asked you to go through section 1 first, was to give you a better understanding what the “Learning AI” part actually meant.</p><p>If you choose to go with the <em>first path</em> (section 1.1), you will end up using and getting <strong>accustomed</strong> to several AI tools. This will be like, for example, learning how to use Google Sheets and then jumping onto using MS Excel.</p><p>Perhaps your employer/supervisor/professor wants you to switch to a new tool because it has more features than the last one, or simply because you have decided to move onto something else on your own. In any case, keeping up with new tools and services (which are popping out like moles in a half-eaten farm nowadays) will make you present-proof rather than make you future-proof.</p><p>If you decided to go with the <em>second option </em>(section 1.2), and you have confidence that this is the path you want to spend the rest of your life on, then congratulations, you have got the first step covered.</p><p>But just like as was in the previous case of keeping up with new tools, here you will be keeping up with new technologies (assuming that you are now past the point of getting software development skills and studying machine learning).</p><p>If you were building or contributing to the technologies that other developers use, then you might have a good chance of keeping ahead of some technologies, but then it is the “near future” we are talking about, and not 2077 🦾. These technologies we speak of, gets updated with tons of new features almost every week. So yeah, that is also present-proof instead of future-proof.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZQtdVVwAlQg1Tac3mEO_w.png" /></figure><h3>3- Skilled Individuals With Experience In IT Field</h3><p>Having good knowledge of technologies gives these people an edge over non skilled individuals or those individuals who do not concern themselves with the field of IT.</p><p>There are various options on how these people can upgrade themselves such that they can perform a career switch or to add a new technology to their list of skills.</p><p>As explained in section 1.1, the first path will be relatively easy for these individuals as they are more tech oriented and have a much more thorough <strong>observation habit </strong>of judging the behaviour of the service or the application they are using.</p><p>These services can obviously help them in enhancing their productivity and enable them to do more in less time.</p><p>But the second path (section 1.2), may prove to be more difficult for varous reasons. Some of the reasons are shown below:</p><ul><li>They might <em>deviate </em>from their initial career path.</li><li>They might waste time depending on the <em>complexity </em>of the technology they are learning. Since they also have their day job.</li><li>New tools, libraries, and algorithms are released frequently, requiring them to constantly learn and adapt to the technologies in <em>parallel </em>to the technologies they are already keeping up with.</li><li>There is a lot to learn, so there is a good chance that without proper guidance, the individual may be overwhelmed with a plethora of technologies to learn in mid-career phase.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/655/1*zPSUHbxVpMM9Q5uqWCuRTg.png" /></figure><p>So … the answer?</p><p>Going with the first path (section 1.1) is easy for them as it saves more time on their end and even makes them productive. The second path (section 1.2) however, is a lot more riskier for the working individual.</p><p>If you have read section 2, you would already know that both of these paths to “Learning AI” will get you nowhere near being future-proof. But there are some things you gain from it as well.</p><h4>What Benefits IT People Can Get If They “Learn AI”</h4><p>You might <strong>unlock opportunities</strong> for yourself if you wish to switch careers. In this case, you will be loved by employers as you would have both Software Development expertise and knowledge of Machine Learning.</p><p>It would be relatively easier for you to get an ML Engineer job rather than a fresh candidate with no prior experience.</p><p>Still you should understand that Machine Learning or AI related jobs are as much as <em>in demand</em> as the Software Development jobs. Learning new AI technologies and use them to build projects only expands your skillsets and makes you a bit more knowledgeable about different technologies.</p><p>And as you might have guessed already, learning AI in mid-career is not really that necessary, because even without it you would already be fit for a variety of roles in the software development industry.</p><p>Yes, there is a rising concern about<strong> jobs being replaced</strong> or automated by AI technology, and I also plan on addressing that here.</p><p>Things which are likely to get automated will certainly get automated. That said, ChatGPT, Github Copilot and BARD can write code by learning from us humans. That is very concerning isn’t it?</p><p>Now look at this problem from an <strong>employer’s perspective</strong>. Instead of hiring an employee, they can use ChatGPT to write code, but it comes with a lot of drawbacks that employers are not happy about:</p><ul><li>ChatGPT, Github Copilot or BARD are <strong>not efficient </strong>in coding complete applications and performing change requests … yet. They may be in the future but not now.</li><li>The <strong>resources they consume</strong> to write a few lines of code is <em>massive</em>. Plus if they choose to use more than one bot to write code for them it scales their costs.</li><li>Setting these bot services up and serving them around the globe can only be done by multi-billion dollar companies (it costs a fortune) like Google or Microsoft. The employers <strong>can’t have it for free</strong> and with the same efficiency.</li><li>Basically the employers would be hiring robots outsourced by top-tech companies which can raise their <strong>pricing schemes</strong> anytime and the employers won’t have a say in this.</li></ul><p>Although there are a bunch more reasons as well, but you get the gist of it.</p><p>And look, if the employers believed that they can get cheap and efficient labor out of robots, they would have done so years ago. After all, the only thing that any business stands for, ultimately, is making a profit.</p><blockquote><em>📌</em> Some companies do actually care about their customers and their experience. But they can’t care for them if they don’t have a revenue. So yeah it boils down to profits.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZQtdVVwAlQg1Tac3mEO_w.png" /></figure><h3>3- Skilled Individuals With Experience In Fields Other Than IT</h3><p>These individuals cannot go for the path described in section 1.2 unless they wish for a job switch. Even in that case they would need solid conformation that they would get hired for a technical role if they learned how to use this technology or that and gained some computer science knowledge. This obviously does not seem plausable.</p><p>These individuals may be the experts of their fields such as accountants, project managers, HR, artists, writers etc and may even have used a few softwares before to their work. But they are <strong>not technical experts</strong> like their typical IT guy.</p><p>For them, the only feasible way to “Learn AI” is to learn to use the AI services (as I have mentioned before in section 1.1).</p><p>At this point you already know the answer if you have been reading everthing up till now, that learning this or that technology or skill cannot make you future proof.</p><p>I have seen people market their courses like “<em>AI is the future and learning AI will make you future proof</em>”. If you are on a senior role in your company, you would know that this is not true at all.</p><p>Yes, learning how to use new software which has more features than the last one is a choice that every business makes. Learning new things can give you an edge over other candidates.</p><p>And no, prompt engineering is not something you can learn, but rather it is something that you already know. You talk to a bot in English and it replies to you in English. The better you define your question the better the answer gets. That is all there is to it.</p><p>Plus it is not a skill that people will get hired for. CEOs know of this and they would probably burden someone they already hired, with prompt engineering or using some other AI service rather than hiring someone entirely new for the job.</p><p>You need to understand that, there is still a reason you have your day job. Higher order of critical thinking, decision making and emotional intelligence is not something AI can mimic. Not yet anyways.</p><p>For those new to the domain of IT, I have already written a blog which explains the hype of current rise in AI technology.</p><p><a href="https://medium.com/@hammad.ai/dont-believe-the-hype-understanding-a-i-trends-2023-non-technical-guide-fb5988874919">Don’t Believe The Hype: Understanding A.I. Trends 2023 (Non-Technical Guide)</a></p><blockquote><em>📌</em> I have debunked the myth of prompt engineering in the blog above as well.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZQtdVVwAlQg1Tac3mEO_w.png" /></figure><h3>If Only The Future Were As Simple As Learning Some AI Algorithms And Calling It A Day!</h3><p>Don’t get me wrong, AI skills are hot these days, but let’s not kid ourselves — they’re not a magic shield against the ever-shifting winds of the economy.</p><p>If you really care about being future-proof, then here is my personal opinion how to become just like that:</p><ul><li><strong>The adaptability of a chameleon 👉</strong> The world is changing faster than a Kardashian’s hairstyle, so you better be ready to switch gears at a given time. Gone are the days of one-track careers — be prepared to learn new skills, embrace new technologies, and maybe even pivot your entire career path if the need arises.</li><li><strong>The resilience of a cockroach 👉</strong> Life throws curveballs, and the future economy will be no different (as far as we can see from the present). Get ready for economic downturns, job changes, and even the occasional robot uprising (probably not … maybe). The key is to be mentally tough, bounce back from setbacks, and keep moving forward. When you find the doors closed, look for ways to open them, instead of waiting tor them to be opened.</li><li><strong>The creativity of a mad scientist 👉</strong> Forget about rote memorization and textbook knowledge (AI can do that better now)— the future belongs to those who can think outside the box, generate innovative ideas, and solve problems in unconventional ways. Let your inner Picasso loose and embrace your weirdness — it might just be your ticket to success.</li><li><strong>The empathy of a social worker 👉</strong> As AI takes over the mundane tasks, human skills like communication, collaboration, and emotional intelligence will become even more valuable. Learn to work effectively with others, understand their needs, and build strong relationships — these are the skills that will make you truly irreplaceable.</li><li><strong>The audacity of a con artist (but without the conning, of course) 👉</strong> Never underestimate the power of a good hustle. Be proactive, network your butt off, and shamelessly promote yourself. In a crowded marketplace, you need to stand out and make a name for yourself. Learn about what people around you need and help them. You might even erect a business with this approach.</li></ul><p>Now, let’s address the elephant in the room — those AI enthusiasts who preach future-proofing through algorithms. While AI skills are undoubtedly valuable, they’re just one piece of the puzzle.</p><p>Remember, robots may be able to crunch data and write code, but they can’t replace the human touch, the spark of creativity, or the ability to connect with others on a deeper level.</p><p>Being future-proof is not about learning this or that, but rather cultivating yourself such that you can take on the uncertainties of life like your better self. Learning from your mistakes is no different.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VZQtdVVwAlQg1Tac3mEO_w.png" /></figure><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know 📣 your thoughts on it. I’d love to listen to your feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d8e45d1b51f8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tuning Model Hyperparameters With Random Search]]></title>
            <link>https://medium.com/@dev-in-trenches/tuning-model-hyperparameters-with-random-search-f4c1cc88f528?source=rss-b773ad9709f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/f4c1cc88f528</guid>
            <category><![CDATA[hyperparameter-tuning]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[randomsearchcv]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Dev In Trenches]]></dc:creator>
            <pubDate>Sat, 25 Nov 2023 20:59:50 GMT</pubDate>
            <atom:updated>2023-11-25T20:59:50.145Z</atom:updated>
            <content:encoded><![CDATA[<h4>A Comparison with Grid Search</h4><p>If you don’t already know, I have recently posted about Grid Search being a valuable tool for hyperparameter tuning. But as every other tool, it has its drawbacks.</p><h4>TL;DR</h4><p><a href="https://en.wikipedia.org/wiki/Random_search">Random Search</a> is a hyperparameter optimization technique in machine learning that randomly samples a defined number of hyperparameter combinations from specified distributions. By distributions, I mean sets or ranges of possible parameter values.</p><p>It efficiently explores a subset of the hyperparameter space, making it faster and more <em>resource-efficient</em> than exhaustive methods like grid search.</p><p>While it might not guarantee finding the absolute best hyperparameters, it effectively discovers good settings, especially in scenarios with large or complex parameter spaces or sets are considered.</p><p>Here I will introduce you to Random Search, tell you <em>how it works </em>and how it <em>compares to grid search</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*M24XYSuRGHEWgOCN" /><figcaption>Photo by <a href="https://unsplash.com/@sloppyperfectionist?utm_source=medium&amp;utm_medium=referral">Hans-Peter Gauster</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>What is it?</h3><p>Random or Randomized Search is a searching algorithm which is modified to work with different sets of hyperparameter values in a machine learning model.</p><p><a href="https://en.wikipedia.org/wiki/Hyperparameter_(machine_learning)">Hyperparameters</a> are settings that aren’t learned during the training process but affect the behavior and performance of a machine learning model.</p><h3>Minor Throwback To Grid Search?</h3><p>In my previously related article, where I explain about <a href="https://medium.com/@hammad.ai/using-grid-search-for-hyper-parameter-tuning-bad6756324cc?source=your_stories_page-------------------------------------">Using Grid Search For Hyper-Parameter Tuning</a>, we were giving the algorithm a list of values to select from (generally called a grid of values), and it would try <em>every </em>possible combination of those values with our model to find out the optimum settings (hyperparameter).</p><h3>How Does It Work?</h3><p>Randomized Search, as the name suggests, picks a parameter value at random from a <em>range</em> or <em>list</em> of possible values for a specific hyperparameter.</p><p>A little disclaimer … I will be demonstrating this with RandomForestClassifier() which can be obtained from sklearn.ensemble. The data I’m going to be using with this model is none other than the iris dataset obtainable from sklearn.datasets as load_iris.</p><blockquote><em>📌 </em>Also, make sure you have split the dataset into training and testing sets before you begin. You will soon know why you need this.</blockquote><pre>from sklearn.datasets import load_iris<br>from sklearn.ensemble import RandomForestClassifier<br>from sklearn.model_selection import train_test_split</pre><h4>Step 1: Define The Parameter Space Or Distribution</h4><p>To define a distribution, we only a python dictionary which contains the parameter name as the KEY and the range of possible values as the VALUE for those keys.</p><p>Pretty easy start, huh? Take your time reading the comments below:</p><pre># Define hyperparameter distributions<br>param_dist = {<br>    &#39;n_estimators&#39;: [int(x) for x in np.linspace(start=200, stop=2000, num=10)],  # Number of trees<br>    &#39;max_features&#39;: [&#39;auto&#39;, &#39;sqrt&#39;],  # Number of features to consider for best split<br>    &#39;max_depth&#39;: [int(x) for x in np.linspace(10, 110, num=11)],  # Maximum depth of the trees<br>    &#39;min_samples_split&#39;: [2, 5, 10],  # Minimum samples required to split a node<br>    &#39;min_samples_leaf&#39;: [1, 2, 4],  # Minimum samples required at each leaf node<br>    &#39;bootstrap&#39;: [True, False]  # Whether bootstrap samples are used when building trees<br>}</pre><p>For the range of parameter values, you will need to use python lists. Since these are lists, we can also use <em>list comprehensions </em>to help us create a lengthy list, just like I have done with list for n_estimators.</p><blockquote><em>📌</em> Please take note that I’m using numpy here in some lists. You are free to use whichever methods you like. But if you are going to follow along, you will need numpy installed.</blockquote><h4>Step 2: Prime The Random Search Object</h4><p>We can get the RandomizedSearchCV object from the same module we got our train_test_split from.</p><pre>from sklearn.model_selection import RandomizedSearchCV</pre><p>Note that the name of the Class we are importing has a CV in the end. This means that it comes pre-packed with <a href="https://en.wikipedia.org/wiki/Cross-validation_(statistics)">Cross-Validation</a>, just like Grid Search. And that is why we needed train_test_split to slice our dataset into training and testing sets.</p><p>If you are not familiar with the cross-validation technique, you basically split your dataset into multiple subsets (folds), train the model on some of them, and evaluate it on others. This helps ensure that the model’s performance is robust and not just tailored to the training data.</p><pre># Create a Random Forest Classifier<br>rf_classifier = RandomForestClassifier()<br><br># Create the RandomizedSearchCV object<br>random_search = RandomizedSearchCV(<br>    estimator=rf_classifier,<br>    param_distributions=param_dist,<br>    n_iter=100,  # Number of parameter settings that are sampled<br>    cv=5,  # Number of cross-validation folds<br>    verbose=2,<br>    scoring=&quot;accuracy&quot;,<br>    random_state=42,<br>    n_jobs=-1  # Use all available processors<br>)</pre><p>There are a lot of things going in here, so let’s walk through this slowly.</p><p>RandomizedSearchCV takes an argument named estimator which is the model we want to use.</p><p>param_distributions is the dictionary we prepared earlier.</p><p>n_iter signifies the number of iterations to run. The higher the value, the better the results are, but it will also take more time as well. There is a trade-off here, so you should plan on using an optimum and acceptable value. Default is 10.</p><p>cv represents the number of folds we should perform for cross-validation. If nothing is provided, it will be set to a default value, which is 5.</p><p>Adding a verbose argument will show you the progress of the search being performed. It accepts an integer value from 1 to 3. It will give you more detailed logs of what is going on. Here is what each one does:</p><ul><li>1 👉 the computation time for each fold and parameter candidate is displayed</li><li>2 👉 the score is also displayed</li><li>3 👉 the fold and candidate parameter indexes are also displayed together with the starting time of the computation</li></ul><p>scoring is the metric which will be considered for determining the best results. If this is not provided, the default will be selected based on the estimator you have selected. In case of Random Forest Classifier, it is “<em>accuracy</em>”.</p><p>random_state is for random, uniform sampling from lists of possible values. It accepts a random integer.</p><p>n_jobs represents the number of jobs to run in parallel. Since this is an iteration based process, we can allow it to run some jobs in parallel to cut down on the processing time. -1 means use the maximum number of jobs that can be run on the current processor. Default is 1.</p><p>To keep it from getting more complex than it already is, I have skipped some arguments that RandomizedSearchCV can take. But know this:</p><ul><li>refit allows you to define your custom scoring function.</li><li>pre_dispatch controls the number of jobs that get dispatched during parallel execution.</li><li>return_train_score accepts a boolean which represent whether the training score will be calculated or not. This can cut down on the training time.</li></ul><blockquote><em>📌</em> You can learn more about these arguments in <a href="https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html">SKLearn’s Official Docs</a>.</blockquote><h4>Step 3: Fit The Data &amp; Extract The Results</h4><p>The hard part is over. Now we will simply fit the model with the training dataset.</p><pre># Fit the RandomizedSearchCV instance<br>random_search.fit(X_train, y_train)</pre><p>Let’s get the results …</p><pre># Retrieve the best parameters found by RandomizedSearchCV<br>best_params = random_search.best_params_<br>print(&quot;Best Parameters:&quot;, best_params)<br><br># Evaluate the model with best parameters on the test set<br>best_estimator = random_search.best_estimator_<br>test_accuracy = best_estimator.score(X_test, y_test)<br>print(&quot;Test Accuracy with Best Parameters:&quot;, test_accuracy)</pre><p>best_params_ is a dictionary which may look like this:</p><pre>{<br>  &#39;n_estimators&#39;: 2000, <br>  &#39;min_samples_split&#39;: 10, <br>  &#39;min_samples_leaf&#39;: 2, <br>  &#39;max_features&#39;: &#39;sqrt&#39;, <br>  &#39;max_depth&#39;: 10, <br>  &#39;bootstrap&#39;: True<br>}</pre><p>Notice it is using the same name we used while defining param_dist.</p><blockquote><em>📌</em> Unlike in Grid Search, where I showed you a heatmap with all the values of the grid, I won’t be plotting any charts here. This is simply because Random Search is not systematic like Grid Search, so plotting a bunch of RANDOM values will not essentially tell us anything useful.</blockquote><blockquote><em>Thank you for reading till the end 🥳</em></blockquote><p>Now you are able to find the best parameters for your model more quickly and efficiently … in a more <em>processor friendly</em> manner than the Grid Search.</p><p>If you found this article helpful and learned something new, be sure to leave a 👏 or let me know 📣 your thoughts on it. I’d love to listen to your feedback.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f4c1cc88f528" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>