Blog

  • 5 Vim plugins you might need for everyday work

    5 Vim plugins you might need for everyday work

    I switched to NeoVim entirely only four months ago. That wasn’t too hard for me. I was preparing for years without even knowing that. I had a few reasons for that switch, but two of them are the most important.

    First, I wanted to have an efficient workflow without constantly changing a tool in my hand: it is really distracting for me. I was trying to achieve it using shortcuts, plugins for IDEA/PhpStorm, etc., but the process wasn’t complete. I always felt gaps.

    The second reason was the need to move somewhere from JetBrains products, as they decided to not allow Russians to use their products for political reasons. But that’s a common decision in the business area nowadays, so I don’t blame them. Especially, because they made me to do that important step, eventually.

    Many years ago, I realized that Vim was my favourite editor for editing files remotely, so basic movements and quitting weren’t a problem for me. However, working with projects looked like a nightmare to me. Watching ThePrimeagen’s videos, I found that even tools that come out of the box with Vim can solve the problem. NetRW is a simple and powerful tool.

    But it is not enough when you want to quickly switch between files. So I added Telescope and Harpoon to my tool set. First help to find anything in the project, the second is really helpful when you do an actual work and have to switch between more than 2 files.

    I can’t imagine my work without linters and language servers. I’ve set them up a few times from scratch, but there were different tiny issues that I didn’t know how to fix. Eventually, I came across LSP Zero, which did all the hard work for me. Accompanied by Mason, it leaves you almost with no work to do for setting it up properly.

    I have to mention Treesitter, which makes code look better, and Copilot which, generally, makes life easier, but, honestly, I can survive without them.

    The one I use rarely, but every time I’m happy I know about it is undotree. You know, sometimes you appear in a situation when you went into a wrong direction while coding and you want to find a place where things went wrong. Here it comes on the scene, providing an accessible (in my understanding) way to work with the changes history.

    The last plugin isn’t required at all. But I enjoy it. And it helps me to improve my Vim skills. vim-be-good. Try it. I believe you’ll fall in love.

  • ClockInterface – why we need it and how to use?

    ClockInterface – why we need it and how to use?

    A few months ago a new standard was proposed to PSR and then accepted. Its name is PSR-20: Clock.

    And here is a short introduction from that document:

    Creating a standard way of accessing the clock would allow interoperability during testing, when testing behavior that has timing-based side effects. Common ways to get the current time include calling \time() or new \DateTimeImmutable('now'). However, this makes mocking the current time impossible in some situations.

    Basically, it explains everything you need to know. I came across an extremely similar solution on my previous work. “Great minds think alike.”

    The solution is really simple. Just look at the proposed interface:

    namespace Psr\Clock;
    interface ClockInterface { 
        /** * Returns the current time as a DateTimeImmutable Object */ 
        public function now(): \DateTimeImmutable; 
    }

    Let’s briefly consider how to use it in our “application”.

    First, we need to implement that interface:

    namespace ExampleApp\Clock;
    use Psr\Clock\ClockInterface;
    class DateTimeClock implements {
        public function now(): \DateTimeImmutable {
            return new DateTimeImmutable();
        }
    }

    And now we can use it in our application code:

    namespace ExampleApp\Log;
    use ExampleApp\Clock\DateTimeClock;
    use Psr\Clock\ClockInterface;
    class Entry {
        public function __construct(
            public \DateTimeImmutable $time,
            public string $message
        ) {}
    }
    class Logger {
        public function __construct(private ClockInterface $clock) {}
        public function createEntry(string $message): Entry {
            return new Entry(
                $this->clock->now(),
                $message
            );
        }
    }
    class LoggerFactory {
        public function __invoke(): Logger {
            return new Logger(
                new DateTimeClock()
            );
        }
    }

    Without ClockInterface we would probably just create a new instance directly: new \DateTimeImmutable(). And that would be really hard to test. Tests for calls to system API become tricky and flaky. But with the new interface, they become much easier and stable:

    namespace ExampleAppTest\Log;
    use ExampleApp\Log\Logger;
    use PHPUnit\Framework\TestCase;
    use Psr\Clock\ClockInterface;
    class LoggerTest extends TestCase {
        public function testCreateEntry_MessageGiven_ReturnsMatchingEntry(): void {
            $clock = $this->createMock(ClockInterface::class);
            $clock
                ->method('now')
                ->willReturn(
                    new \DateTimeImmutable('@1')
                );
            $logger = new Logger($clock);
    
            $entry = $logger->createEntry('a');
    
            $expected = [
                'time' => 1,
                'message' => 'a',
            ];
            self::assertSame($expected, $this->exportEntry($entry));
        }
        public function exportEntry(Entry $entry): array {
            return [
                'time' => $entry->time->getTimestamp(),
                'message' => $entry->message,
            ];
        }
    }

    Just imagine how you’re trying to catch a second or testing the period without this interface and tests fail in CI, because they run too slow or for any other reason. Probably you decide not to test time then and at some point it appears that a bug was introduced exactly in this place.

    I suggest considering using this new interface and make your life just a bit happier.

  • How to build a WordPress theme with ChatGPT and Bing

    How to build a WordPress theme with ChatGPT and Bing

    AI is everywhere. It helps you with generating ideas, fixing and improving texts, even writing texts from scratch. And the only thing you need to do – is ask them.

    Can you build a nice looking design for a blog using tailwindccs?

    Recently, in one Russian-spoken podcast, I heard they only can’t write a plugin for WordPress. However, in internal chats of the company that I work for, I heard that one colleague accomplished to write a plugin for scratch using ChatGPT.

    I didn’t have an idea for a useful plugin, but I want to get a new theme for this blog. I asked AI to help with that.

    can you build a nice looking design for a blog using tailwindccs?

    ChatGPT answered with 7-bullet list of general pieces of advice on how to prepare a markup using TailwindCSS. That wasn’t what I expected.

    One more try:

    can you generate markup for my wordpress blog?

    And I got another six suggestions, this time about HTML tags that might be useful.

    But, again, I expected something specific…

    I command!

    I realized what was my mistake: I asked them if they can and got pretty general responses. I need to change wording to get anything new:

    Generate the markup for the front page of my blog using TailwindCSS

    ChatGPT responded with an actual HTML code that looked like a grid of posts with previews!

    Awesome!

    like it, make it look more like a professional site

    ChatGPT added a few details to the initial markup. I suppose nobody says the design is anyhow professional, but I got it for free with a little time to spend.

    This time I’m going to build a theme!

    Cool, thank you. Write a WordPress theme from it, please.

    But it looks I was too kind to them: I got a list of actions on how to convert that markup into a theme.

    Okay, I committed the same mistake again. It’s time to fix it:

    Let’s try again: convert the markup to a wordpress theme.

    This time I got the same seven list items, but supplemented with real code excerpts.

    Following the instructions, I took the pieces and put them into files.

    The last step was to add a minified TailwindCSS file.

    npx tailwindcss init tailwindcss-config.js

    Tiny changes to look for content in PHP files inside the same folder and we’re ready to generate CSS.

    npx tailwindcss -c ./tailwindcss-config.js -o tailwind.min.css -m

    I tested the theme on this blog and realized that I also need a single post template.

    This time, I asked Bing to help with that.

    build html markup for my professional blog using tailwindcss

    Unfortunately, Bing is not built for writing code. However, it wrote an article with an example of markup for the post. (Actually, my prompt is not good, and it doesn’t have any clue about the single post.)

    I took that HTML and fed it to ChatGPT:

    Okay, I have markup for a single post: {html-here}. Convert it into theme’s single post template.

    No problem, I got a ready-to-use code with a few comments, describing what it has utilized here and how I can use this template.

    Committed and pushed into the repo: https://github.com/merkushin/wp-ai-theme. Check it out 🙂

  • Vim bindings in my browser

    Vim bindings in my browser

    Oh, I got used to Vim bindings so much! I think half of my work time I spend in NeoVim, so those bindings become my second nature.
    And because of that, working with text in Chrome (actually, it is not the single browser for me, but it is the default one at work) becomes less and less convenient.

    A few days ago I decided that it’s enough, and I have to find a solution. Previously, I heard about approaches to use you NeoVim inside your browser.

    I started looking for exactly this solution, and soon I found Firenvim. It wires your NeoVim with your browser. I was so excited! Until I tried to edit the description for my pull request on GitHub. It appeared to be a bit glitchy and I couldn’t use Cmd+V to insert some text from my clipboard. I’m pretty sure it was possible to solve those problems, but I decided to look farther, for something more native for the browser. I think I’ll come back to Firenvim later, but at the moment it is too much for me.

    I opened to Chrome Web Store and typed “vim mode” in. Markdown Anywhere appeared a very surprising solution for me. Its main purpose isn’t provide Vim-bindings, but to make editing of Markdown in browser more comfortable. At the same time, it provides bindings and does it perfectly.

    A short remark here: I had to search for “vim bindings” there to get more expected results.

    I checked Google with the same keywords: “vim mode”. And it brought Surfingkeys in front of my sight. This plugin solves the problem of navigation in the browser using Vim-bindings (and even more).

  • DI doesn’t always mean IoC

    DI doesn’t always mean IoC

    Dependency injection is sometimes confused with dependency inversion. However, the former is only an implementation detail for both dependency inversion and inversion of control.

    Dependency injection is a useful technique to introduce dependencies in your code. It might be one class we want to use in another one, or it might be a service from an external library that we want to call in our controller. And it is the way to make dependency inversion possible.

    However, dependency inversion is the term of a higher order. Now we talk about dependencies in a broader scope, not about concrete classes, but about abstractions behind them. This time we want to use TimeInterface in our PublishingInterface, but not about the DateTime class (or time function) in the FacebookPublisher class. Using interface and class terms here, I want to oppose concrete implementation versus abstractness. We usually solve the coupling problem in our architecture by using the dependency inversion.

    When we think about the inversion of control, we actually stop considering dependencies, and start working with the control flow. It is about keeping uncertainty as long as possible. Keeping that uncertainty, we approach decoupling and code reusability.

    Dependency injection is a way to approach dependency inversion in a clean manner, and also one of many options when you think of how to apply the inversion of control in your architecture.

  • PhpStorm Useful Hot Keys (for me)

    PhpStorm Useful Hot Keys (for me)

    Below is my tiny cheat sheet for PhpStorm. Knowing and using hot keys improves productivity significantly. I used to use them before started using IdeaVim, as many of these hot keys conflict with Vim bindings.

    This post was in drafts here for at least three years, and it bubbled up during my last revision. I decided to publish it in case it is useful for someone.

    Recently, I was forced to move out from PhpStorm and other JetBrains products, because Russian citizens aren’t eligible to pay for various products and services. I was a loyal customer of JetBrains products for years, and now, when my last two-years license was about to end, I had to consider moving to something else. I used IdeaVim plugin for the last few years, and moving to NeoVim was natural for me.

    Hot keys

    F1 – quick documentation;
    Opt + F7 — find usages;
    Cmd + P — show parameters;
    Cmd + D — duplicate string;
    Double Shift — search everywhere & Cmd + O — search class;
    Cmd + Opt + T — surround with dialog;
    Cmd + Opt + L  — reformat code;
    Cmd + Shift + Enter — complete construction;
    Cmd + E — recent files;
    Double Opt + Arrow — add multiple carets;
    Tab (inside parenthesis or braces) — jump outside closed parenthesis/brace.

    Refactorings

    Ctrl + T — refactoring popup;
    Shift + F6 — rename class, variable, field, constant …;
    Cmd + F6 — change signature;
    Cmd + Opt + M — extract method;
    Cmd + Opt + F — extract field;
    Cmd + Opt + C — extract constant;
    Cmd + Opt + V — extract variable;
    Cmd + Opt + N — inline variable.

    Compare files

    Select files in the Project window and press Cmd + D.

    Terminal

    Open terminal, switch terminal tabs: https://stackoverflow.com/a/31631338/206729

  • An alternative for a DI-container in WordPress plugin development

    An alternative for a DI-container in WordPress plugin development

    Briefly, the dependency injection helps us to work with dependencies: makes them observable and enables to substitute them whenever we need it.

    My choice of preference is to inject dependencies through a constructor. Here, we have both the observability and the replaceability. As a bonus, the object is completely instantiated and ready for future work. However, it becomes harder to create new objects and our code significantly suffers if we try to do that in a straightforward fashion by adding a few arguments to the constructor call. As we (usually) want to maintain testability and flexibility of our code, we have to extract the creation of the object in a factory.

    The popular approach here is to use the DI-container for that purpose. The major PHP frameworks, like Laminas and Symfony, have their own implementations. Sometimes they can handle everything for you: you just have to configure the container and follow a few simple rules. There are also framework-agnostic solutions that you can add to the app.

    About a year ago, I joined Automattic and dived into WordPress plugin development. I found a lot of traditions and conventions here. From my perspective, some of them are outdated, sometimes are toxic (in terms of software health) and need a revision. For example, it is really hard to write unit tests there. If you check popular plugins’ code you probably find some unit tests, but those are a mixture of integration tests and unit tests. I will not develop this topic here, but it might be interesting to discuss it later.

    I started experimenting with writing testable code, but the conventional approach of creating objects and introducing dependencies was blocking. To write a “pure” unit test, you need to have an opportunity to substitute the dependency, and that’s hard when it is instantiated deep in the roots of your logic.

    I tried to introduce a DI-container in my experimental project, but it turned out that you need to carry the container everywhere through the code to make it available. One option was to make it global: use global variable sounded terrible for me. Another version of the global state here was to use a function from the global state or a singleton.

    I tried to find a tradeoff. But then I realized that I don’t need a container as an external library. If I’m okay with a static factory, it is easier to write the simple one on my own.

    I remembered that approach from The Art of Unit Testing by Roy Osherove.

    You create a class with a static method that creates an instance of a class and returns it. However, you also have an option to substitute the returning value: for tests, for example.

    If you’re interested in how to implement this approach, you can check WPAL, my attempt to build an abstraction over the WordPress API.

    Here is the excerpt from the ServiceFactory class that creates the implementation for the Hooks abstraction:

    class ServiceFactory {
        /**
         * @var Hooks|null
         */
        private static $custom_hooks;
    
        public static function set_custom_hooks( ?Hooks $hooks ): void {
            self::$custom_hooks = $hooks;
        }
    
        public static function create_hooks(): Hooks {
            if ( self::$custom_hooks ) {
                return self::$custom_hooks;
            }
            return new WpHooks();
        }
    }

    The worst part of this approach, from my point of view, is that you create dependencies inside the constructor of a dependant. Not providing those dependencies through constructor’s arguments, we make them less visible. If you look at the constructor’s code, everything is well observable, and the object is completely ready for use after the constructor call. So, that’s my trade off here.

    This is how the usage of the ServiceFactory looks like:

    class Example {
        /**
         * @var Hooks
         */
        private $hooks_api;
    
        /**
         * @var string
         */
        private $plugin_file;
    
        public function __construct( string $plugin_file ) {
            $this->plugin_file = $plugin_file;
            $this->hooks_api = ServiceFactory::create_hooks();
        }
    
        public function init() {
            $this->hooks_api->add_action( 'init', [ $this, 'register_taxonomies' ] );
            $this->hooks_api->add_action( 'init', [ $this, 'register_post_types' ] );
        }
    
        public function register_post_types(): void { /* ... */ }
    
        public function register_taxonomies(): void { /* ... */ }
    }

    And the test for the init method:

    final class ExampleTest extends TestCase {
        public function testInit_WhenCalled_AddsAction(): void {
            $hooks_api = $this->createMock( Hooks::class );
            ServiceFactory::set_custom_hooks( $hooks_api );
            $contacts = new Contacts( 'a' );
    
            $hooks_api
                ->expects( $this->exactly( 2 ) )
                ->method( 'add_action' )
                ->withConsecutive(
                    [ 'init', [ $contacts, 'register_taxonomies' ] ],
                    [ 'init', [ $contacts, 'register_post_types' ] ]
                );
            $contacts->init();
        }
    }

    Talking about downsides of this approach, I can think about the global scope where the factory operates. On the other hand, DI-containers represent the same global scope problem, but covered with object-oriented tricks.

    Using a static factory looks preferably for me in the WordPress plugin development as we don’t have to bring another external dependency to the app, and the complexity of the solution looks relatively lower (comparing to learning, introducing and using the DI-container).

  • But these conflict with your requirements or minimum-stability

    Today I struggled with updating the library in the project. I just raised the version of this package, and now I was constantly getting:

      Problem 1
        - The requested package x/yz (locked at 1.2.3, required as ^1.2.4) is satisfiable by x/yz[1.2.3] but these conflict with your requirements or minimum-stability.

    I couldn’t understand anything at all because there were no stability changes, no sub-dependencies, and so on. I accidentally noticed a typo in my command:

    composer update x/yc --ignore-platform-reqs

    (the letter c instead of z at the end of the library name)

    But there is no such typo in the error message, and the error is not about a missing dependency.

    If you are experiencing the same problem but there is no typo, please read the article on the topic (ru).