Http Hobo

Another blog with web-development tips’n’tricks. | About me

First big update for Mapkeen

Hi,

Since my last post I have been actively working on Mapkeen introducing more cool features. And finally it comes – first big update. If we put it short – now you can add cities and towns onto your map there.

New features:

  • Ability to add visited cities and towns (includes stats)
  • Ability to add cities and towns user lived in (includes stats)
  • New map look
  • Supported highlighting of Australian states
  • Added ability to embed map

Here is an example of embedded map which presents all of the new features:

Hope you are going to love it. Go ahead and start your profiles on Mapkeen right away. And stay tuned for more updated.

Thanks,
George

2019   mapkeen   my releases

Advice: don’t overwhelm with configurability

Hey there,

Today I want to talk about configurability. I was installing our main project onto a new server and using our self-checker tool to verify the installation. During that process we talked with other developer and realized that path for our minifier output is configurable, yet checker won’t recognize that and will always check default one.

Which brings us basically to two choices – improve checker (more obvious) or make this path hardcoded (less obvious). When I thought about this more and talked about this with the colleague, we realized that this setting has never being changed on any of our installations. So we have a flexibility which we don’t need. And more than that – we have to maintain that flexibility, and yet it’s not going to pay out.

Another thing to think about is when config goes into client’s hands. It’s not the case for all, but sometimes it happens and client has to configurate the system. The more settings and options the client has, the harder it is to maintain the config or even understand which option means what.

So I make a rule:

When you want to make something configurable – think in which case it might be needed. If there is no realistic scenario – hardcode it

Best regards,
George

2019   advice

Presenting my own project: Mapkeen – travellers network

Hi all,

Although it’s active work in progress, I’m happy to present a project I’ve recently launched – Mapkeen. Before I tell you about the project, couple words about myself.

During the last 4 years, I had an opportunity to travel to different countries. Those were not casual travels, I had to live for several months in a bunch of those. So-called “slow-travelling”. This has quickly became my passion and caused an addiction, however this kind of drug is nothing but good – exploring the world, widening knowledge of different cultures and people. I love this so much, so I wanted to share something with people I’ve been friends or relatives with.

Now let’s turn on some imagination. My family and friends – they all live in different countries on 3 different continents. The more I travel, the more stories, pics and vids I have. Imagine telling those a bunch of times – that won’t be much fun. So I thought – what if I create an application to get all people together and give them an opportunity to share their travel stories?

Here comes Mapkeen. The BIG idea is not yet implemented – I’m still working on it. However, right now you would be able to create a profile and start creating your trip history. Every trip has dates, destinations and you can add a story to it. Thanks to the way this information is gathered, visited destinations get highlighted on your map, also some stats are provided. The more we work, the more interesting the map and stats are to become.

If you share my love and passion for travels, please join Mapkeen. You can either subscribe for news there or follow this blog as new features are to be release soon. The one we currently have been working on is to make map show not only whole countries, but visited regions and cities as well. Also we keep working on making the application more reliable, stable and quick.

If you have ideas, thoughts or any other input, please feel free to share in comments. I will highly appreciate that!

Thanks,
George

2019   mapkeen   my releases

EMLIAF: Object Oriented Programming

Hi all,

EMLIAF stands for Explain Me Like I Am Five. I have been tutoring for a while, and realized that there are a lot of things in the programming world that nobody really bothered to explain in a human-friendly way. I’ll try to feel that gap, who knows if I’m good at that.

First I will start with Object Oriented Programming (OOP in short), as it is a very basic concept. Basically OOP is a way to organize data storage and operations with the data.

OOP is based on two pillars: classes and objects.

Class
It’s basically a blueprint, set of rules. Imagine we are producing a car of a particular model. That model blueprint is basically a class. You cannot do anything with the blueprint other than building a car based on it. That would be an object or a class instance.

Object
Since an object is an instance of a class, it doesn’t have any rules, it follows them. However, this is something storing data and functionality, so it can be used. There can be multiple objects of a single class, i.e. there can be thousands of cars of a particular model. You cannot ride a blueprint (class), but you can ride a car (object).

Objects basically store data and provide functionality. Data is stored in “properties”, functionality is provided in “methods”.

Property
Car has a lot of properties, i.e. color, maximum speed, number of wheels. All the properties are defined in class, but values are set in object. I.e. there can be multiple cars of the same model but with different colors. Property can also contain another object. Imagine we also have an *engine* class, and several different engine objects – less powerful and more powerful. Car can have a property with a value pointing to a particular engine object. Engine will have it’s own properties and methods too.

Method
Basically a function attached to an object. Methods are defined in class, and they normally operate with properties. Methods can call other methods. Imagine a car having a method “turn on”, property “engine” pointing to an engine object, and engine having a method “ignite” and property “working” which is Boolean (“Yes”/“No” type). Now when we call car’s “turn on” method, the following happens:

  • Engine’s method “ignite” is called
  • “Ignite” method sets engine’s property “Working” to “Yes” and returns signal of success back.

That’s basically how classes and objects work. However, there are three important concepts in OOP: encapsulation, inheritance and polymorphism.

Encapsulation
Have you seen those movies where a car thief messes with some wires trying to ignite it? He uses a so-called “private” method. This method is not supposed to be called by an object user, it’s supposed to be called internally. I.e. you shouldn’t mess with the wires, you should press the button or put a key in and turn it. Pressing the buttons or using a key would be so-called “public” method. This is encapsulation – defining responsibilities and scope for methods and properties. It is important to keep correct state of things. Imagine car engine’s “working” property is set to “yes”, whereas the gasoline tank is empty. This creates an error state, and encapsulation is used to prevent it. Engine’s “working” property should be private, so you cannot just change it however you want. Method “turn on” should be public though, it would check if there is gasoline and only after that set “working” to “yes”. This ensures correct flow of data in the program.

Inheritance
Imagine a car manufacturer. Some regular one. It produces a bunch of different car models. However, all these models are still cars. Does manufacturer need to put all basic car specifications in every model’s blueprint? No. Because there is a class “Car” and every model class inherits from it. So the “Car” class will basically define everything common for all the cars, and then children classes will add details. “Car” class will have such properties as “engine”, “transmission”, “number of wheels”, etc. Model class will have properties like “body type”, “interior”, etc.
Now let’s get back to encapsulation. There are three levels: “private”, “protected” and “public”. “Private” is restricted to a particular class, i.e. car’s private methods can be called by car class instances only. “Protected” is restricted to a class itself, also to it’s parent and children classes,, i.e. car’s protected methods can be used by model class instances too. “Public” is allowed to be called by anybody.

Polymorphism
I couldn’t make a good example with cars for this. Instead imagine a multitool – it has knife and a screwdriver. Let’s make it classes: first would be “knife”, it has method “cut”; second would be “screwdriver”, it has method “screw” and “unscrew”. Multitool can do all. Polymorphism means ability to exist in different forms, and multitool can be a knife and screwdriver at the same time. Some happens in programming, there can be a class which basically can inherit from multiple other classes.

Basically that’s it for the Object Oriented Programming. Important to understand that:

  1. Not all programming languages support OOP, and among those supporting not all support it fully.
  2. There are more details like interfaces, different additional access levels like “private protected”, static methods, etc. This is out of scope of this article, it’s purpose is to only give an idea of a concept.

Let me know in comments if this is useful and clear. Do you want to have more articles like this?

Greetings,
George

Angular 2+ async validation getting stuck in PENDING state?

Hey all,

Haven’t been having anything really interesting to cover here until today. I was implementing async validation in an Angular 7 application, and got stuck with it not really working.

My observations:

  • Request to the server is made, and my AsyncValidationFn gets executed, it returns an Observable successfully.
  • Map operator used with the observable works correctly.
  • Form control doesn’t get any errors

I investigated further and found out that form control status gets stuck in PENDING state. I googled a bit and realized that Observable is not completing, that’s why. I was a bit pissed, why this wasn’t covered in the documentation, but then it was:

Just like synchronous validators have the ValidatorFn and Validator interfaces, asynchronous validators have their own counterparts: AsyncValidatorFn and AsyncValidator.

They are very similar with the only difference being:
* They must return a Promise or an Observable,
* <strong>The observable returned must be finite, meaning it must complete at some point. To convert an infinite observable into a finite one, pipe the observable through a filtering operator such as first, last, take, or takeUntil.</strong>
* It is important to note that the asynchronous validation happens after the synchronous validation, and is performed only if the synchronous validation is successful. This check allows forms to avoid potentially expensive async validation processes such as an HTTP request if more basic validation methods fail.

However, it’s weird that their example misses using any of the “filtering” operators, that was the culprit. Fixed my code, and everything now works like a charm.

Was:

export function emailUniqueValidator(jsonRpc: JsonRpcService, auth: AuthService): AsyncValidatorFn {
    return (control: AbstractControl) => {
        return jsonRpc.sendRequest<Boolean>('api1.user.is-email-taken', {
            email: control.value,
            user_id: auth.identity.id
        }, {
            headers: auth.getAuthorizationHeader()
        }).pipe(
            map(isTaken => {
                return isTaken ? {emailTaken: true} : null
            }),
            catchError(() => {
                return null;
            })
        );
    }
}

Is:

export function emailUniqueValidator(jsonRpc: JsonRpcService, auth: AuthService): AsyncValidatorFn {
    return (control: AbstractControl) => {
        return jsonRpc.sendRequest<Boolean>('api1.user.is-email-taken', {
            email: control.value,
            user_id: auth.identity.id
        }, {
            headers: auth.getAuthorizationHeader()
        }).pipe(
            map(isTaken => {
                return isTaken ? {emailTaken: true} : null
            }),
            catchError(() => {
                return null;
            }),
            first()
        );
    }
}

Best regards,
George

JSON-RPC implementation for Yii2

Hi there!

I’m currently working on a mobile application, and initially I used REST approach for client-server communication. However, it quickly started to drive me nuts as REST has a lot of flaws and in my opinion is not nice at all. In short – because it’s too hard to have transactions for operations. So I decided to move to JSON-RPC protocol. I considered GraphQL (seems a little bit overkill for my current needs), gRPC (you can’t have gRPC server written on PHP, so porting my existing Yii2-based server solution would take too much time), but JSON-RPC is the simplest and quickest way to go.

However, I haven’t found any Yii2 extension for this which I would like. Main thing I didn’t like is that existing extensions don’t use Yii2 power and features. That doesn’t make sense because why not go with standalone JSON-RPC server then?

So I wrote my own extension which translates “method” string to a route and then executes an action. Therefore Yii2 is used as usually, just with different entry point.

Let’s say we have the following controller:

<?php
namespace app\modules\api1\controllers;

class ExampleController extends \yii\web\Controller {

    public function actionTry() {
        return "You've got it!";
    }

    public function actionTryWithParams($foo) {
        return "Params received: \$foo = $foo.";
    }

}

Calls and responses would look like the following:

-> {"jsonrpc": "2.0", "method": "api1.example.try", "id": 1}
<- {"jsonrpc": "2.0", "result": "You've got it!", "id": 1}

-> {"jsonrpc": "2.0", "method": "api1.example.try-with-params", "params": {"foo": "bar"}, "id": 2}
<- {"jsonrpc": "2.0", "result": "Params received: $foo = bar.", "id": 2}

-> {"jsonrpc": "2.0", "method": "api1.example.garbage", "id": 3}
<- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": 3}

-> [
	{"jsonrpc": "2.0", "method": "api1.example.try", "id": 1},
   	{"jsonrpc": "2.0", "method": "api1.example.try-with-params", "params": {"foo": "bar"}, "id": 2},
	{"jsonrpc": "2.0", "method": "api1.example.garbage", "id": 3}
   ]
<- [
	{"jsonrpc": "2.0", "result": "You've got it!", "id": 1},
   	{"jsonrpc": "2.0", "result": "Params received: $foo = bar.", "id": 2},
	{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": 3}
   ]

Check it on GitHub or use with Composer (note that it’s only alpha available now as I’m still working on the extension and testing it):

"repositories": [
        {
            "type": "git",
            "url": "https://github.com/georgique/yii2-jsonrpc/"
        }
    ],
    "require": {
        "georgique/world-geojson": "*@dev"
    }
]

P.S.: Couldn’t post extension to official Yii2 site because rules are just insanely stupid there, which I will write another post about.

Advice: preparing for production launch

I was talking to my friend and ex-colleague today. He is a team lead, and we were discussing a forthcoming launch of a product his team is working on. He shared his worrying with me – launching a product and being so responsible for it is a new experience for him.

I had this experience. More than two years ago I have successfully launched a system for accepting and processing online immigration applications for one of Canadian provinces. Our system has several components, and I was not only writing a code for one of them, but also integrating all the components into one platform. I wasn’t head of the project, but I was technically responsible for the launch. And what I can tell now after that launch and bunch of other update launches afterwards is that it’s not that scary as it might seem.

I think it’s clear that the most worrying thing is possible errors. Especially those which can corrupt data. Well, don’t worry. It’s just this simple. Instead of worrying, take preventive actions. I already hear you opposing me that you have been fixing errors all the time, but they just keep appearing from nowhere. That’s the point of this post – it’s unlikely you will release your software without errors. I love this joke (originally it was in Russian and probably sounds better):

There were 100 bugs in the code
One we have fixed
Is it less now?

So in addition to fixing bugs in your code, you need to do something else in order to prepare for the launch.

In order to prepare for launch, not only keep fixing errors, but prepare instruments for fixing errors AFTER the launch.

Let me explain. I did couple things before the launch and they saved a bunch of my nerves because I was ready:

  1. I introduced a very sophisticated logging system and was writing every user’s action into it. A lot of records were redundant and I am still cleaning them, but log records saved significant amount of time while investigating into issues, trying to understand user’s actions and even restoring some data, because log records could contain some IDs of objects which had been deleted at the moment of investigation. By the way I don’t have direct access to production server.
  2. I made efforts to make things as smooth for user as possible. I know that hiding errors is not a good approach. Empty catch section is something a programmer often should be thrown out of the office. But making things smooth for end user is another story. User is not responsible for errors in your code. Hide errors from user and instead expose them to your development branch. Log records, status reports, integrity checks – create and use instruments to monitor your system, but don’t bother user with your problems. If users are not affected, you win time for possible investigations, because users won’t overwhelm your support, so your support won’t overwhelm you.

And to put your worry to the ground completely, I can tell you – that if you do your work well, chance of critical errors appearance will be low enough. Do your best to prevent critical errors impacting end users and/or system stability, then prepare yourself for fixing all other issues. Because they will happen anyway. There is nothing to worry about. It’s just part of our job.

P.S. If you are from NASA, Airbus, Boeing or any other company working on a product which people’s lifes and well being depend on, neglect everything you just read. You don’t have right for errors, sorry.

2017   advice

Angular 2+ service doesn’t feel being shared across components?

Probably the reason is that you’ve declared it as a component provider, not app provider. Shared service has to be declared in app.component.ts in “providers” section:

@NgModule({
  declarations: [
    // Some declarations
  ],
  imports: [
    // Some imports
    RouterModule.forRoot(
        appRoutes,
        { enableTracing: true }
    )
  ],
  providers: [
      YourService,
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

If you declare it in component declaration like this:

@Component({
    selector: 'my-component',
    templateUrl: './templates/my-component.component.html',
    providers: [MyService],
})

then a fresh instance of a service will be created, instead of using a app-wide one.

If you need a service instance shared across components, declare it app-wide. If you need a distinct service instance for a component, declare it as a component’s provider.

2017   angular

My opinion about Ionic Framework

Recently I started to dig into mobile app development. I had to find a framework for creating hybrid application and I picked up the most popular one – latest Ionic.

Ionic is a wrapper for PhoneGap/Cordova framework. Cordova is a framework turning JS-based app into mobile app. You can say Cordova is a layer between your JS app and mobile phone. Ionic adds Angular 2 support + visual components library for your app.

Ionic is quite easy to start with if you know Angular 2. You won’t need a lot of special knowledge, most of struggling would be about working with mobile hard and software. But that would be that kind of struggling which makes sense only in case you are doing something really simple or a prototype.

Ionic’s tempting with one code base for all mobile platforms. Well, universality is an enemy of quality. You will finally found out that:

  • Some functionality is still device-specific
  • Some functionality is just missing (no cordova plugin)
  • Some functionaliy is specific to device native API version
  • Ionic app UI won’t work as smoothly on device as native one does

So when your app is simple, all these things you can ignore. For the prototype it’s still may be good choice – one codebase for different platforms might be a strong pro. But for the serious application you will just have to struggle and suffer a lot. And if struggle and suffer anyway, why don’t go with native app?

Script execution exit code is 126, but permissions are good

I have PHP script which calls bash script using exec() function. Worked well until recent release. When I checked logs, I found that the script is now exiting with code 126.

Documentation says that exit code 126 is reserved and it means that command cannot be executed. Comment elaborates, that this is permission problem or command is not an executable. Besides that I googled the problem, and most of the comments over the Internet is that it’s about permissions. Said that, it’s not surprising that my eyes caught only first part of the comment about permissions.

We checked script permissions – they were totally ok. Then I found out that parent directories’ permissions also matter, checked them – also all good. Then checked permissions of a binary being called by our script – good too.

When we tried to execute the script from CLI, we’ve got the following error:

-bash: path/to/script.sh: /bin/bash^M: bad interpreter: No such file or directory

You see ^M? That’s our guy. ^M is also known as CR or \r – Windows line-ending. When it’s somewhere in the script it usually doesn’t cause problems. But it’s presence in shebang could not be excused, so we’ve got exit code 126. That’s that part of the documentation saying “command is not an executable”.

If you get exit code 126 and permissions look good, check line endings.

2017   unix
Ctrl + ↓ Earlier