megacolorboy

Abdush Shakoor's Weblog

Writings, experiments & ideas.

9 Software Books I'm Reading This Year to Become a Better Engineer

As a software engineer, continuous learning is essential. The tech industry evolves rapidly, and keeping up requires a commitment to improving skills, refining best practices, and understanding the deeper principles behind great software design. This year, I’ve curated a list of nine must-read books that will help me become a better developer, architect, and problem solver.

If you're looking to level up your software engineering skills, these books might interest you too:

The Pragmatic Programmer

By Andrew Hunt & David Thomas

"Care about the code you write and the people who will maintain it after you."

A foundational book that every developer should read. It provides practical advice on coding, debugging, and automation, making you a more adaptable and efficient engineer.

Designing Data-Intensive Applications

By Martin Kleppmann

"A well-designed system grows gracefully as the dataset, traffic volume, or complexity increases."

A must-read for backend engineers and system architects, this book explores data modeling, distributed systems, and scalability challenges.

Clean Code

By Robert C. Martin

"Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code."

Writing clean, maintainable code is a core skill for developers. This book offers practical techniques for improving code quality.

The Mythical Man-Month

By Frederick P. Brooks Jr.

"Adding manpower to a late software project makes it later."

A classic in software project management, this book explains why adding more people to a late project only makes it later.

Refactoring

By Martin Fowler

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."

A practical guide to improving existing code without altering its functionality, making it more readable and maintainable.

Domain-Driven Design

By Eric Evans

"The heart of software is its ability to solve domain-related problems for users."

This book teaches how to align software design with business logic, making complex software systems more manageable.

Working Effectively with Legacy Code

By Michael Feathers

"To change software means to change behavior. Our goal is to do so safely."

If you’ve ever had to deal with old, complex codebases, this book provides strategies for refactoring without breaking functionality.

Why Programs Fail

By Andreas Zeller

"Every bug has a cause, and every cause has a cure."

A systematic approach to debugging, helping developers diagnose and fix software defects effectively.

Extreme Ownership

By Jocko Willink & Leif Babin

"Leaders must own everything in their world. There is no one else to blame."

Leadership and accountability are critical for engineers working in teams. This book teaches how taking full responsibility leads to success.

Final Thoughts

These books cover a wide spectrum of skills—from writing clean code and designing scalable systems to debugging, refactoring, and leadership. By reading and applying the lessons in these books, I aim to become a better software engineer this year.

Laravel Scopes vs. Builder Queries: Which Should You Use?

If you're building a Laravel application, you're probably spending a lot of time writing queries. And as your project grows, you'll inevitably face this question: Should I use scopes or builder queries? While both have their place, choosing the right tool for the job can make a world of difference. Here's my opinionated take on the matter.

The Case for Scopes

Scopes are, quite simply, one of Laravel's hidden gems. They let you encapsulate common query logic within your models, making your code clean, reusable, and easy to read. Think of them as tiny, purposeful functions designed to save you time and sanity.

Take this example:

<?php
    // In your model
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    // Usage
    $activeUsers = User::active()->get();
?>

Suddenly, instead of littering your controllers with where('status', 'active') everywhere, you have a single, reusable method that reads like English. Scopes shine when you need commonly used filters like active, published, or recent. They’re easy to use, they’re consistent, and they make your code feel more intuitive.

Why I Prefer Scopes for Reusability

Here’s the thing: in any sizable Laravel app, you’ll inevitably find patterns in your queries. Rewriting the same query logic over and over? That’s a code smell. By using scopes, you centralize your query logic, reducing redundancy and improving maintainability.

For example:

<?php
    $pubishedPosts = Post::published()->recent()->get();
?>

This reads beautifully and keeps your codebase DRY (Don’t Repeat Yourself). If the definition of "published" or "recent" changes, you only need to update it in one place. Scopes turn repetitive query logic into single lines of magic.

The Case for Builder Queries

That said, not everything belongs in a scope. Some queries are just too specific, too complex, or too dynamic. This is where builder queries come in.

Imagine you’re building a report that requires multiple joins, conditional logic, or dynamic filters. Scopes could become unwieldy here. Instead, a well-crafted builder query in your controller, service, or repository might make more sense:

<?php
    $users = User::where('status', 'active')
        ->whereDate('created_at', '>', now()->subDays(30))
        ->orderBy('created_at', 'desc')
        ->get();
?>

Builder queries are perfect for:

  • One-off operations.
  • Highly dynamic queries.
  • Scenarios where scopes would make your models bloated or overly complex.

The flexibility of builder queries is unmatched. You can construct them on the fly, adapt them to user inputs, and handle edge cases without worrying about making your models an unreadable mess.

My Opinionated Take: Use Scopes as a Default, Builder Queries for the Edge Cases

If I had to pick a side, I’d say: lean on scopes as your default tool, and reserve builder queries for those rare cases when scopes just don’t cut it. Why?

  1. Scopes enhance readability. Your queries read like sentences, and your intentions are crystal clear.
  2. Scopes promote DRY principles. They’re reusable and encapsulate logic, which makes future maintenance a breeze.
  3. Builder queries are powerful but can become messy. Unless you’re careful, a complex query in your controller can grow into a sprawling monstrosity. Keep your controllers lean and delegate to scopes or dedicated query classes where possible.

When Not to Use Scopes

There are times when using a scope might do more harm than good:

  • Too much complexity: If a scope needs multiple parameters or involves complex joins, it’s better suited as a custom query builder or a dedicated repository method.
  • Rarely used logic: Don’t clutter your models with scopes for queries that are only needed once or twice.
  • Dynamic, user-driven queries: When filters are highly variable, builder queries give you the flexibility you need.

Conclusion: Balance Is Key

Laravel gives you powerful tools to write queries, and both scopes and builder queries have their roles. Use scopes to simplify and centralize reusable logic, and reach for builder queries when flexibility and complexity demand it. By balancing both, you’ll keep your codebase clean, maintainable, and a joy to work with.

So, what’s your take? Are you a scope enthusiast or a builder query champion? Either way, Laravel’s got you covered.

A Starter Guide to Software Version Control

Version Control Systems (VCS) are indispensable tools for modern software development. When I first started working with version control, I was overwhelmed by the terminology and the various workflows. Over time, I realized that mastering VCS isn't just about understanding commands—it's about adopting practices that make development smoother and more collaborative. In this post, I’ll share my journey, the lessons I’ve learned, and a practical approach to version control that works for teams of any size.

What is Version Control?

I remember my first experience losing hours of work because I accidentally overwrote a file. That’s when I discovered the magic of version control. It’s like having a time machine for your code! At its core, version control tracks and manages changes to your software code. Here’s why it’s essential:

  • Collaborate with ease: Gone are the days of emailing files back and forth. Multiple developers can work on the same codebase without stepping on each other’s toes.
  • Track every change: With a detailed history of changes, debugging becomes less of a nightmare.
  • Rollback anytime: If something breaks, you can revert to a stable version in seconds.

Today, tools like Git, Subversion (SVN), and Mercurial are popular choices, with Git leading the pack. If you haven’t tried Git yet, you’re missing out on a developer’s best friend.

Key Concepts

Here’s a quick glossary that helped me when I was starting out:

  1. Repository: Think of this as your project’s home. It stores your code and its entire version history.
  2. Commit: A snapshot of your code changes. A good commit is like leaving breadcrumbs for your future self or teammates.
  3. Branch: This was a game-changer for me. Branches let you work on new features or fixes without touching the main codebase.
  4. Merge: When you’re ready to bring your work back into the main project, merging combines it with the existing code.
  5. Tag: These are like bookmarks, marking specific points in your project’s history—perfect for releases.

Types of Branches

When I joined my first team project, I was introduced to a branching strategy that revolutionized the way I worked. Here’s how it breaks down:

1. Main Branches

  • Main (main or master): This is the crown jewel—the stable, production-ready branch. It’s sacred territory where only thoroughly tested code belongs.
  • Development (dev): This is where the magic happens. New features and fixes are integrated and tested here before they’re ready for production.

2. Feature Branches

When you’re working on something new, create a feature branch. Here’s how it works:

  • Purpose: To develop a specific feature.
  • Workflow: Start from dev, and when you’re done, merge back into dev.
  • Naming Convention: feature/new-login-system

3. Release Branches

Preparing for a new release? Here’s what you do:

  • Purpose: To finalize a version for production.
  • Workflow: Start from dev, do final testing and fixes, then merge into main.
  • Naming Convention: release/v1.0

4. Hotfix Branches

Production bugs can’t wait. That’s where hotfix branches save the day:

  • Purpose: To fix critical issues in production.
  • Workflow: Start from main, fix the issue, then merge into both main and dev.
  • Naming Convention: hotfix/login-bugfix

A Practical Workflow Example

Here’s a typical workflow I follow:

  1. Feature Development: Let’s say I’m building a new login system. I’d create a branch called feature/new-login-system off dev. Once the feature is complete and tested, I merge it back into dev.
  2. Preparing for Release: When it’s time to launch, I’d create a branch called release/v1.0 from dev. After some final tweaks, I merge it into main and tag it as v1.0.
  3. Production Hotfix: If a bug pops up in v1.0, I’d create a branch called hotfix/login-bugfix from main. Once fixed, I’d merge it into both main and dev and tag it as v1.0.1.

Best Practices

Here are some lessons I learned the hard way:

  1. Write Clear Commit Messages: Your future self will thank you. A good message explains what changed and why.
  2. Keep Commits Small: Each commit should represent a single, logical change. This makes debugging a breeze.
  3. Review Before Merging: Always use pull requests or merge requests. Two heads are better than one.
  4. Use Tags for Releases: Tags are lifesavers when you need to rollback or track changes.
  5. Backup Your Repository: This might sound obvious, but don’t take it for granted.

Why Version Control is a Game-Changer?

For me, version control transformed how I approach coding. It made collaboration smoother, debugging faster, and deployments safer. Whether you’re working solo or with a team, adopting a thoughtful version control strategy is a must.

Final Thoughts

Version control is more than just a tool—it’s a mindset. By following the practices and strategies outlined here, you’ll be well on your way to mastering it. Trust me, your future self—and your teammates—will thank you.

Cicada 3301

A short docu-series about one of the most mysterious puzzles on the internet.

Ever heard of Cicada 3301? It's one of those mysterious puzzles that made every crypto enthusiast around the globe turn into super sleuths hunting for clues and chasing the next puzzle. I was quite interested in it after watching this series of documentaries titled Cracking the Code of Cicada 3301 that shot by Great Big Story, which made my interest towards my cryptography grow larger.

Although, I never tried this series of puzzles myself, the actual host of this puzzle is unknown as some claimed that it could be a recruitment programme by the FBI/CIA/NSA/GCHQ to hire super smart individuals or maybe some crypto/security group that cares about data privacy and security.

I remember watching this series back in 2020 and it was quite hard for me to find these videos and hence, I'm sharing it here for you and my reference as well (in case, I wanted to re-watch the documentary again):

What I liked about this documentary series is how it connects people of various disciplines such as Mathematics, Programming, Linguistics and Steganography to deduce and decipher a really complex puzzle. I just find that inspiring because knowledge is power and when aligned with people of similar interests and ambitions, you build new bridges of friendship that spans around the globe.

Hope you liked reading this article.

Don't forget what sparked your passion

A short letter to myself and other fellow programmers.

Do you ever remember falling in love with programming when learning to code during school days or while working on a client's project? Probably not.

When I started learning to code, I never wrote code because I wanted to but because I desired to. No one to poke me around with tight deadlines, no need to race against time. Just the feeling of power and creativity in your hands to build something out of nothing but just pure code. It could have been anything as simple as building a small widget for my blog post, writing a game, solving a problem in LeetCode or Project Euler or maybe writing a bash script to automate my tasks.

You could probably relate to some but for me, these are some of the examples that resonate with me.

I'm writing this as a reminder to myself and other fellow programmers: don't ever forget that moment when your passion for programming had sparked. You might be older now and you're probably filled with a lot of responsibilities (especially if you're parenting).

Perhaps, you might never even experience that same amount of adrenaline and rush that you had when you were behind the computer in your room while your siblings and friends were trying to distract you.

There's never an end to learning. You can still find some passion projects that'll help you keep that spark. Have an open mind and be open to newer ideas. Solve a puzzle, read a book, write a game or maybe a blog post.

Don't do this because you need to impress someone or for the sake of it rather because you can and it brings you joy.

Oh and wishing you a Happy New Year! 😀🎄

Clean Controllers in Laravel: Best practices for handling form submissions

Learn how to write clean Laravel controllers for efficient contact form handling using validation, Eloquent, Mail, and events.

Unlike most frameworks, Laravel is an unopinionated framework and doesn't force the developer to follow a particular pattern.

In this article, I'm going to show you how your codebase could benefit by following Laravel's best practices like separation of concerns, utilizing Laravel's in-built features like Eloquent models, Form Requests and Mail.

To begin with, here's a dirty method that handles a simple contact form submission:

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class ContactController extends Controller
{
    public function submit(Request $request)
    {
        // Validate the form inputs
        $request->validate([
            'name' => 'required',
            'email' => 'required|email',
            'message' => 'required',
        ]);

        // Get the form data
        $name = $request->input('name');
        $email = $request->input('email');
        $message = $request->input('message');

        // Save the form data in the database
        DB::table('contact_forms')->insert([
            'name' => $name,
            'email' => $email,
            'message' => $message,
        ]);

        // Send an email to the user
        $mailData = [
            'name' => $name,
            'email' => $email,
            'message' => $message,
        ];

        Mail::send('emails.contact', $mailData, function ($message) use ($email) {
            $message->to($email)->subject('Thank you for contacting us');
        });

        // Return a response to the user
        return redirect()->back()->with('success', 'Thank you for contacting us! We will get back to you soon.');
    }
}

To most developers, this method might seem straight-forward and they might even debate with you that it's completely fine. But allow me to highlight the issues of that this method brings to the table:

  1. Lack of separation of concerns: The controller is responsible for handling form validation, saving data to the database, and sending an email. This violates the Single Responsibility Principle.

  2. Direct usage of the database query builder: Instead of utilizing Eloquent models for database interactions, the example directly uses the query builder, which can make the code less maintainable and harder to read.

  3. Inline email sending: The email sending functionality is implemented inline within the controller method, making the code harder to test and reuse.

  4. Lack of error handling: The example does not handle any potential errors that may occur during form validation, database insertion, or email sending.

Now, it's time to make it cleaner.

Save data using Form Requests and Laravel's Eloquent ORM

Let's start with creating a form request that is dedicated to handling the validation logic:

  1. Quickly, open up your terminal and type the following command:
php artisan make:request ContactFormRequest

This command will generate a new file named ContactFormRequest.php in the app/Http/Requests directory.

  1. Open the ContactFormRequest.php file and modify it as follows:
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactFormRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        // Set the authorization logic based on your requirements
        // For example, you may check if the user is authenticated or has certain permissions.
        // Return true if the user is authorized to submit the form; otherwise, return false.
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required',
            'email' => 'required|email',
            'message' => 'required',
        ];
    }

    public function messages()
    {
        return [
            'name.required' => 'Please enter your name',
            'email.required' => 'Please enter your email address',
            'email.email' => 'Please enter a valid email address',
            'message.required' => 'Write a message before submit the form',
        ];
    }
}

In the rules() method, you can define validation rules for each field in the form. You can adjust according to your own preferences and if you want to know more about them, read this documentation.

  1. Save the ContactFormRequest.php file.

Great, now you have a separate class for validating your contact form and this promotes code-reusability, improves code readability and separates the validation logic from your controller.

Now let's update the submit() method in the ContactController.php example:

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Http\Requests\ContactFormRequest;
use App\Models\ContactFormModel;

class ContactController extends Controller
{
    public function submit(ContactFormRequest $request)
    {
        // Validate the form inputs
        // All of the validated form data is accessible via this property.
        $validated = $request->validated();

        // Save the submission
        ContactFormModel::create($validated);

        // Send an email to the user
        $mailData = [
            'name' => $name,
            'email' => $email,
            'message' => $message,
        ];

        Mail::send('emails.contact', $mailData, function ($message) use ($email) {
            $message->to($email)->subject('Thank you for contacting us');
        });

        // Return a response to the user
        return redirect()->back()->with('success', 'Thank you for contacting us! We will get back to you soon.');
    }
}

Ensure that you have an appropriate model for your contact_forms table like ContactFormModel.php and update the following like so:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class ContactForm extends Model
{
    protected $table = 'contact_forms';

    // Define any additional model configurations, relationships, or methods.
    protected $fillable = [
        'name',
        'email',
        'message'
    ];

    protected $timestamps = true;
}

This allows you to leverage Laravel's ORM in which you could benefit from easy quering, relationship management and automatic timestamps.

Making use of Laravel Events and Mail

  1. Generate a new event class by writing the following artisan command:
php artisan make:event ContactFormSubmitted

This will generate a ContactFormSubmitted class in the app/Events directory.

  1. Open up ContactFormSubmitted.php file and update as follows:
<?php
namespace App\Events;

use App\Models\ContactForm;
use Illuminate\Foundation\Events\Dispatchable;

class ContactFormSubmitted
{
    use Dispatchable;

    public $contactForm;

    /**
     * Create a new event instance.
     *
     * @param  ContactForm  $contactForm
     * @return void
     */
    public function __construct(ContactForm $contactForm)
    {
        $this->contactForm = $contactForm;
    }
}
  1. Next, let's generate an event listener using artisan command:
php artisan make:listener SendContactFormEmail --event=ContactFormSubmitted

This command will generate SendContactFormEmail event listener in the app/Listeners directory.

  1. Open the SendContactFormEmail.php file and update as follows:
<?php
namespace App\Listeners;

use App\Events\ContactFormSubmitted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Mail;
use App\Mail\ContactFormSubmitted as ContactFormSubmittedMail;

class SendContactFormEmail implements ShouldQueue
{
    use InteractsWithQueue;

    /**
     * Handle the event.
     *
     * @param  ContactFormSubmitted  $event
     * @return void
     */
    public function handle(ContactFormSubmitted $event)
    {
        $contactForm = $event->contactForm;

        // Send an email to the user
        Mail::to($contactForm->email)
            ->send(new ContactFormSubmittedMail($contactForm));
    }
}
  1. Create a mailable class using the following artisan command:
php artisan make:mail ContactFormSubmitted

This command will generate a new ContactFormSubmitted mailable class in the app/Mail directory.

Now, update the ContactFormSubmitted.php file as follows:

<?php
namespace App\Mail;

use App\Models\ContactForm;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class ContactFormSubmitted extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;

    public $contactForm;

    /**
     * Create a new message instance.
     *
     * @param  ContactForm  $contactForm
     * @return void
     */
    public function __construct(ContactForm $contactForm)
    {
        $this->contactForm = $contactForm;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->subject('Thank you for contacting us')
            ->view('emails.contact')
            ->with('contactForm', $this->contactForm);
    }
}
  1. Let's open up the ContactController.php and import the necessary classes on top:
<?php
use App\Events\ContactFormSubmitted;
use Illuminate\Support\Facades\Mail;
  1. Lastly, update the submit() method as follows:
<?php
use App\Http\Requests\ContactFormRequest;
use App\Models\ContactForm;
use App\Events\ContactFormSubmitted;
use Illuminate\Support\Facades\Mail;
use App\Mail\ContactFormSubmitted;

class ContactController extends Controller
{
    public function submit(ContactFormRequest $request)
    {
        // Validated form data is accessible via the $validatedData property of the form request instance
        $validatedData = $request->validated();

        // Save the form data in the database using Eloquent
        $contactForm = new ContactForm();
        $contactForm->name = $validatedData['name'];
        $contactForm->email = $validatedData['email'];
        $contactForm->message = $validatedData['message'];
        $contactForm->save();

        // Dispatch an event to handle email sending asynchronously
        event(new ContactFormSubmitted($contactForm));

        // Return a response to the user
        return redirect()->back()->with('success', 'Thank you for contacting us! We will get back to you soon.');
    }
}

Ah! Finally, this looks much better now, doesn't it?

By making use of Laravel's Mail method, events and listeners, we've separated the logic for sending emails from the controller. The email is now sent asynchronously using an event and listener combination. This approach improves code organization, maintainability, and scalability.

Hope you found this article to be useful.

Thoughts about ChatGPT and the impact on software developers

Will AI-powered tools replace developers in the near future?

This is something I wanted to address for quite sometime but never got the time to talk about my opinions/views about it.

I have been reading many articles and watching a few videos on YouTube in which the authors often contemplate about the future of developers and whether their jobs might be replaced.

If you think that's the case, I'd like to share one of my favorite quotes that might change your mindset:

Software is just a tool to help accomplish something for people – many programmers never understood that. Keep your eyes on the delivered value, and don’t over-focus on the specifics of the tools. — John Carmack

Ever since, ChatGPT went viral, I (and some of my team members) thought of incorporating it to help educate myself during development.

Will it ever replace humans?

Just like the quote above, software is just a mere tool that helps accomplish your end goals. It definitely isn't going to replace a developer with years of experience, let alone, a human being but rather, as a tool or learning aid to help accelerate our ways of being productive.

There are tools like GitHub Copilot (powered by ChatGPT) that helps developers in troubleshooting, refactoring and solving well-defined problems but however, I feel it still has a long way to be able to solve really complex problems in which otherwise could be solved by a software developer.

I'd say that it's crucially important for you to know and be aware of the capabilities and potential of AI-based tools but not to worry too much about it's impact in the industry.

In my opinion, I'd say that a developer who knows how to be effective using AI-powered tools as a learning aid are more likely to replace an developer who aren't aware of them at all.

Here's another quote from John Carmack:

If you build full "product skills" and use the best tools for the job, which today might be hand coding, but later maybe AI guiding, you will be probably be fine. — John Carmack

It's important to view yourself as a problem solver who uses technology rather than someone who simply "codes" for a living and would get replaced in the near future.

What many people don't realize is that a software developer isn't someone who only writes code but also someone who solves complex problems and makes critical decisions. From my experience, I can tell you that it takes a lot of decisions to go from design to deployment and that involves a team that's made up of various skillsets that includes project management, design, development, QA and deployment.

Currently, AI might be good at solving well-defined or common problems but it can never replace the decision-making needed for a successful project.

Can we trust it?

Not yet. ChatGPT ain't AGI thus it has limitations such as that it "hallucinates" i.e. comes up with random facts or solutions that aren't even logical to the problem defined. Whereas, if you look for the problem on StackOverflow, you're more likely to copy/paste a solution that's already recommended by the community.

Exploring ChatGPT

As I had mentioned above, it's quite good at solving well-defined problems and here are a few examples that has helped saved me time:

  • Refactoring methods and repetitive code
  • Writing a method that validates email using regular expressions
  • Writing a simple image gallery component using ReactJS
  • Helped me learn new languages and concepts faster

Oh yes, it did make plenty of mistakes but with all that said, I think it's a great time to learn something new.

Conclusion

My take is that to not overestimate the progression of AI in the near future and underestimate it's impact in the distant future.

Hope you liked reading this article.

Trying out the Redragon K552 Kumara RGB Mechanical Keyboard

My experiences using a mechanical keyboard for the first time.

Redragon K552 Kumara RGB Keyboard

Yes, I finally did it and bought myself a mechanical keyboard after tirelessly scrolling through Amazon and YouTube for a good keyboard that doesn't hurt my pocket in the long run.

What does it feel like?

Got it delivered yesterday and as I unboxed it, I noticed that the build quality is strong and it's quite a heavy keyboard that has around 18 RGB modes to spice things up a bit.

I got the one with the Outemu Red Switches (More like a Cherry MX Red clones) and since it's a linear switch, the typing experience is buttery smooth and not at all noisy. This should be good for typing in office environments or gamers who like to be fast while playing their favorite games.

Currently, I have one issue with it i.e. that keyboard is a bit high and it kind of tires my wrists after typing for longer sessions but I guess, it can be fixed with a wrist rest (Maybe, a nice wooden one 👀).

On my first try, the keys seemed a bit fast for me as I'm not really used to typing on linear switches, let alone, on a mechanical keyboard. But as of writing this article, I got my speed back up and I have been able to achieve around 75-80WPM.

Conclusion

Apart from that, I'm quite happy about this purchase and would definitely hope that it lasts longer until I get another mechanical keyboard.

If you are looking to buy this keyboard, I'd recommend you to give a shot and see it for yourself because I feel that every programmer deserves to type on a good keyboard.

Stay tuned for more content.