Category Archives: Coding

The Beauty of Decorators

@Decorator Pattern
@Python Wiki: Decorators
@Python Usage

Beautiful Code is being nice

“A set of rules? About Code? Decided by whom? Why? What about (…)?”

If “Beautiful Code” sounds a lot like (sometimes objectionable) social norms, it is because code beauty IS a social norm. Moreover, it is a social norm within a subgroup often reknown for being unsociable. When I started programming, code beauty was just something to ignore while I was “getting things done”.

Then I read “Clean Code”. Then “The Humane Interface”. Then I started reading other people’s code at work. It’s amazing how quickly I gained appreciation for social norms once they had vanished.

My mom once told me to “be nice”; I realized then that it was something I had to apply to code.

Some Features are not nice

The thing about using more involved language features is that I am always concerned the person after me won’t know them, or won’t readily adapt to them. For example, lambda functions are great for code locality, but in some cases, terrible for readability.

Moreover, the “magic” class attributes and functions are not always obvious to someone when they come to a language.

Example:

def get_login_user_info(user):
    if user.is_logged_in():
        with SqlConnectionClass() as conn:
            conn.execute("select foo from bar where ~~~~")

Someone unfamiliar with Python is going to come to this and be confused by parts of the syntax. The “with” statement has multiple “magic” class functions (”enter” and ”exit”) which are called when you run a function. Maybe a future programmer is going to read that as a class init and make some changes in init and get frustrated when conn does not necessarily return what they think should be returned. At this point, they will look up the details on Stackoverflow, and hopefully get familiar with “context managers”.

An educated person shouldn’t necessarily hold back due to the needs of an ignorant person. However, I can see the potential confusion that may arise if this pattern continues. having multiple contexts make it visually unclear where and when they end; moreover, this function has multiple roles, some of which should be stripped out and used across many different functions.

PyCharm helps with the confusion, but I think there is a better way.

Decorators Make Things Beautiful

“…we need to make sure that the statements within our function are
all at the same level of abstraction.” – Robert C. Martin

Decorators make things easier to understand.

Example:

decorators.py

def user_login_required(fn):
    def validate_login_fn(*args, **kwargs):
        if "user_id" in kwargs and "password" in kwargs:
            if check_login(user_id=kwargs["user_id"], password=kwargs["password"]):
                return fn(user_details=get_details(kwargs.get("user_id"), *args, **kwargs)
            raise ValueError("Invalid user_id or password")
        raise KeyError("You must pass the user_id and password as keyword arguments")
    return validate_fn

def db_cursor_required(fn):
    def add_db_cursor(*args, **kwargs):
            # Automatically closes the connection when the function finishes executing
            with SqlConnectionCursor() as cursor:
                # Automatically closes the cursor when this closes.
                with cursor:
                    return fn(cursor=cursor, *args, **kwargs)
        else:
            return fn(*args, **kwargs)

    return add_db_cursor

db.py

@user_login_required
@db_cursor_required
def get_user_foobar(*args, **kwargs):
    return kwargs["cursor"].execute("select foo from bar where ~~~~")

main.py

get_user_foobar(user_id="Foo1", password="")

This significantly more readable.[1] A DB Connection is required. A User Login is required. All aspects related to both are dealt with directly in the decorator function, ensuring the same level of abstraction throughout. You never have to deal with the mental overhead of remembering login functions and the related etails.

[1] Yes, the decorator functions themselves are complicated, but they are destined to be heavily-tested building-blocks for your application. As a result, you can also put in more strenuous (read: less readable) data checks within the login code; as you only have it in one place, it isn’t asking too much to learn it once, as opposed to learning it over and over again.

Incidentally, adding in another layer is not necessarily difficult either, although it may change the variables you need to pass the function.

db.py

@user_login_required
@memcache_check
@db_cursor_required
def get_user_foobar(*args, **kwargs):
    return kwargs["cursor"].execute("select foo from bar where ~~~~")

Decorators are Nice

The first rule of functions is that they should be small. The second
rule of functions is that they should be smaller than that. – Robert
C. Martin

 

I firmly believe that learning a code base becomes easier with decorators, for many reasons.

  1. Decorators enforce consistency; you always pass “user_id” and “password” (for example); not doing so raises an exception.
  2. Decorators force you to use keyword arguments; I ALWAYS find them significantly more readable than the lack. (The people who argue against that are usually highly skilled and experienced programmers – who have never had to follow a poorly designed application built by someone before them)
  3. There is a logical place to start “learning” the code; figure out the decorators, which are always going to be a major aspect of the setup of the code.
  4. Each function can concentrate entirely on one thing (in this case: performing the DB call). If the data being returned is incorrect, you will fix the get_user_foobar function. If the database is not connecting properly, you will fix the db_cursor_required decorator function. If the login data is not being perused correctly, you fix the user_login_required function.

If you never used decorators, or find functional programming to be needlessly complex or unwieldy, you may not “like” this. Dynamically modifying functions is not a cheap process either, computationally-speaking. However, I am sure you will agree that the end function is much smaller. If we can agree on a social contract based on simplifying code and making it easier to read, Decorator are necessary.

The iPad as a High-Latency Second Monitor with Air Display

At work, I’ve been experimenting with standing while coding. ?I do find it far more effective than the alternative, and as an added side-bonus, I don’t feel crippling exhaustion when I get home. ?Unfortunately, the effect of the loss of a second monitor is quite pronounced. ?Whereas I could previously keep information split between two monitors with ease, I am forced to resort to Expose or the Gnome equivalent. ?Not good.

My use of two displays is generally as follows.

Display #1 – Actual work being done.

Display #2 – Information about models / classes / etc… that I don’t get automatically from my text editor (Sublime Text 2)

The iPad through Air Display sucks for #1; the lag is real and irritating. ?For #2, however, it shines. ?I have it open to the appropriate page right now, and it probably helped me shave about 15-30 minutes of research off my daily routine.

Considering how rarely I want to change the content on screen #2, I wonder if using an e-ink screen could be plausible in the near future…

Amusing IE8 / PHPmyFAQ bug

An amusing bug, if only because it took a few minutes to debug as opposed to a few hours.

If users navigated to the newly updated PHPMyFAQ server by name, they layout was broken – but going to it by the IP address would have no such effect. ?There was no weird javascript issue that differed between the two.

It turned out that the server name was listed as an Intranet site, and was being displayed in a different display mode than if one would navigate to it by the IP address alone. ?Disabling intranet auto-detection resolved it, but I am not really sure WHY it happened.

 

Django Views As Classes with Python’s __call__ Magic Method

I have been using Django off-and-on for about 2 years now. I am really liking the direction, but what bugged me (for the longest time) is the re-usability of the view section.

For those unfamiliar with Django views, they are not strictly “MVC” views. If anything, they act more like controllers, and I treat them as such. It should be a piece of cake to reuse code between these, but usually what happened was that I would define a bunch of private view functions and have them referenced by various view functions. It wasn’t exactly the shining pinnacle of my development career.

While reading the code for django-jqchat while working on a project for my client, I rediscovered the python __call__ magic method. This basically permits you to call an instance of an object like a function. With a little effort, I managed to re-organize the code to make it a little more easy to parse. This is not complete and not debugged, but maybe you will find it useful.

Github Gist Link

Force Multipliers and Japanese Programmers

日本語で説明ポスト

Yesterday, over coffee, “R” and I traded stories about Akiba, board games and business. However, the main thing that we wound up talking about was programming, or more exactly, why Japanese companies produce lots of code and little progress. To make a long story short, I’ve come to believe it is a failure of management. A failure to facilitate coding through the use of frameworks that amplify work output.

I mentioned the usual generalizations (Japanese aren’t good coders, the Japanese work environment involves a lot of talking and little doing), but “R” mentioned how he worked in a company where they produced a lot of good code and the project managers took care of the insufferable 3 hour meetings – and to be fair, I have too. So why the problem?

The first clue to us both started with frameworks. “R” spent weeks at one company trying to add table joins to a system which simply had nothing of the kind built-in. This reminded me of similar headaches while spending an year of my own time developing Pinki and only having a small search/listing website by the end.

The big clue to me was Fujitsu – and how they constantly had dozens of systems programmers working on Symbian and other tinpot mobile OSes for each of their feature phones. Particularly with feature phones, there was very little difference between handsets, but programmers had to spend obscene amounts of time doing low-level programming to enable old software to run on new hardware. It was rare for me to see anyone going home before the last train. (These were some of the best programmers in Japan, and they had families – even the “overtime bonus” was not reason enough to stay. )

What all these examples have in common is how companies and people brazenly avoid using programming force multipliers. Fujitsu still uses the old/creaky Symbian OS to this day, even though it is a pain to develop for and has little support / community left (particularly in comparison to Android and Win7). I was stupid enough to try to build a website without a framework, and had to re-solve a half dozen problems. R’s former company had settled on some Japanese-language only ghetto framework even though it had no proper DB layer.

My hypothesis is that a lot of Japanese companies produce little new because they have people solving solved problems over and over again. This is probably because of their inability to assimilate newer frameworks with better communities that automatically solve many of these problems for them.

Maybe this is because the English language barrier. You have billions of English speakers and X% are good programmers. Even if 2X% of Japanese speakers were good programmers, you will never have the depth of talent needed to develop native Japanese language versions of computer languages & the community that goes with them. You are restricted to a subset of frameworks, good or bad, that you can explain to your Japanese unilingual boss. He probably is severely risk-averse and is too old to be familiar with current programming technologies and shortcuts. How do you get him to let you program in Python/Django when he is still using Excel as a datastore (a shockingly common issue in Japan!)

I hear the weeaboos across the world now screaming “what about Ruby!”, but Ruby just proves the point. A Mormon Japanese dude (read: English literate, world-focused, non-Otaku, non-loner mindset) coupled with an excellent framework that gained fame world-wide (Rails). It’s nice that there are great Japanese Rubyists but they are not responsible for the popularity of the language.

There are alternative explanations – no money for advanced training, corporate mandates from backroom deals, fear of open source software, incorrect initial assumptions (IE: Japan is the source of all sorts of world class code), but none of them resonate with me.

If I’m right, the solution isn’t that hard. Give the Japanese programmers proper force multipliers in the form of good frameworks and libraries. Give them good training so they aren’t dependent on Google translator-fu. You will see an improvement.

-edit-

This one post got about 10,000 hits through a kind link on Hacker News. You can follow the discussion there. I do not necessarily agree with everything, but it is all generally thought provoking.

-edit #2-

I’m… honoured to see that somehow this made its way to Slashdot Japan, and was translated into Japanese. どうぞよろしくおねがいします。

-edit #3-
みんなさん、ようこそ。 もし不明なところがあれば、是非日本語でコメントをしてください。