Skip to main content

Ralsina.Me — Roberto Alsina's website

Soft skill: naming things

Intro

There is a some­what ar­bi­­trary sep­a­ra­­tion in tech be­tween soft and hard skil­l­s.

Hard skills are tech­ni­­cal skil­l­s. Know­ing a pro­­gram­ming lan­guage. Un­der­­s­tand­ing a pro­­to­­col. Ex­pe­ri­ence with a spe­­cif­ic piece of soft­­ware. Which is all good and nice, of course. Most of us work­ing in tech en­joy these "hard skil­l­s", or we would work on some­thing else, right?

Soft skills is ev­ery­thing else. Know­ing how to ne­­go­ti­ate your sal­lary? Soft. Be­ing good man­ag­ing your tick­­et­s? Soft. Com­­mu­ni­­ca­­tion? Pre­sen­­ta­­tion of knowl­­edge? Knowl­­edge shar­ing? Soft, soft, soft.

See more about soft skills here.

To­day's soft skil­l?

Naming Things

Which is, of course, one of the fa­mous two hard things in com­put­er sci­ence1

There are on­ly two hard things in Com­put­er Sci­ence: cache in­val­i­da­tion and nam­ing things.

-- Phil Karl­ton

This is an un­der­rat­ed skil­l. Ad­ver­tis­ers and wiz­ards know a good name is a big deal, and once a name is ap­plied, get­ting rid of it is very dif­fi­cult, so it's a good idea to try to get it right (or at least not hor­ri­bly wrong) the first time.

Know your audience

You will see here rules. They are all meant to be bro­ken on oc­ca­sion. Which ones can be bro­ken and which ones can't?

It de­pend­s.

If it's an in­ter­nal tool in a com­pa­ny where ev­ery­one speaks en­glish, then you don't need to spend much ef­fort mak­ing sure it does­n't mean "tes­ti­cles" in ger­man (it's Ho­den, BTW)

If it's a niche open source tool then the rule against ob­scure jokes does­n't re­al­ly ap­ply be­cause there's tra­di­tion.

OTOH call­ing things by of­fen­sive names with in­tent is prob­a­bly al­ways a bad idea.

Where do you draw the line? Well, if I could give you an al­go­rithm for that it would not be a soft skil­l, would it?

Rules For Names

So, what's a good name?

It's not a common word.

Make it easy to google. Please. Make it be some­thing that's not al­ready a much larg­er thing. Do not call your big­int li­brary "Grande". No­body will be able to ask about it with­out be­ing flood­ed by links about tiny singers and large (not not the largest) cof­fees.

So, if you can't come up with a very un­com­mon word ... go to oth­er lan­guages. Go to un­usu­al lan­guages. That, plus con­tex­t, will help.

It's not a "bad word" in another language.

Yeah, that suck­s. But hey, it's al­so hard to fig­ure out in ad­vance. At least check Eng­lish Span­ish and Can­tonese ?

There is a rea­son why the Mit­subishi Pa­jero is called "Mon­tero" in span­ish-s­peak­ing coun­tries.

It's not an obscure joke.

Python is called Python be­cause of Mon­ty Python. Which means the place where you down­load­ed pack­ages was called "The Cheese Shop". And the for­mat for the pack­ages was called a wheel (as in "a wheel of cheese").

Ob­scure jokes have a ten­den­cy to en­cour­age sec­ondary, more ob­scure jokes to the point of in­co­her­ence. Try ex­plain­ing "why is this called a wheel?".

Re­cur­sive acronyms count as ob­scure jokes. Yes.

Make it memorable and descriptive.

Not "Ob­ject Adapter Li­brary"

Not "Lan­guage Ex­ten­sion Pack­age"

Yes, those names are "de­scrip­tive" in a dry, to­tal­ly un­in­for­ma­tive way, but I am go­ing to for­get them in 30 sec­onds and I just made them up right now.

So, use an ar­bi­trary, mem­o­rable name. If it works as a men­motech­nic for what the thing does, bet­ter. Good ex­am­ples:

  • SQLAlche­my: mem­o­rable. It's about SQL. It sug­­gest com­­pli­­ca­­tion and prob­a­bly some su­per­­nat­u­ral in­­ter­ven­­tion will be nec­es­sary.

  • Djan­­go: mem­o­rable.

  • Ru­­by on Rail­s: mem­o­rable. It's about Ru­­by. Ok, so it's not about train­s, but "on rail­s" has metaphor­i­­cal mean­ing.

And yes, this rule 65% of the time col­lides with "not an ob­scure joke".

Make it short

"L­lan­fair­p­wl­l-g­wyn­gyll­gogerych­wyrn­drob-wl­l­l­lan­tysil­i­o­gogogoch En­ter­prise Edi­tion" is bad.

Don't make it too short

"C" is bad (it was good in the 70s!).

Make it clear in context

Nam­ing things is not on­ly about nam­ing soft­ware or things, it's al­so about vari­ables, class­es, and iden­ti­fiers in code in gen­er­al.

  • "i" is of­ten bad
  • "str­First­Name" is al­ways bad
  • "data" is al­ways re­al­ly bad
  • "Ob­jec­tAdapter­In­ter­face" is mak­ing my eyes bleed.

A name is not a de­scrip­tion. So, "str­First­Name" is try­ing to de­scribe "it's a string with the first name in it". What else is it go­ing to be? A boolean? Do you call your pet "dog­Fi­do"?

But a name has to be a name. If you call your dog "dog", then "data" and "i" will look good to you.

And a name is not a DNA test. You don't need to de­scribe the an­ces­try of things, just say what they are. A glass is not a Drink­ing­Wa­ter­Con­tain­er. It's a glass. 2

Name things what they are, or some­thing that lets you iden­ti­fy them. I know, rad­i­cal.

Conclusion

You did­n't ex­pect me to solve one of the hard prob­lem­s, did you? No, I won't. These are just, like I said, rules meant to be bro­ken. But you need to break them con­scious­ly.

For ex­am­ple, I am nam­ing a project of mine Co­braPy. be­cause it's an 80s-style retro thing, and in the 80s Karate Kid was cool, and in Karate Kid there's Co­bra Kai, and that sort of sounds like Co­braPy and Py is for Python, and Co­bras are al­so snakes.

But I named it that on pur­pose.


  1. Which is the source of an in­­­fi­nite num­ber of jokes.  

  2. See This com­ic  

CobraPy? CobraPew! Pew!

It has been a week and I had not re­al­ly touched Co­braPy my 80s-style python en­vi­ronem­nt at al­l. UN­TIL YES­TER­DAY.

So, how is it look­ing now? Like this, us­ing as­sets from the AWE­SOME ken­ney.nl:

I have added:

  • Sup­port for mu­sic (y­ou are lis­ten­ing to 80616-lunchip.xm)
  • Sup­port for sounds
  • Some im­prove­ments to the sprite en­gine (reusing tex­tures and such)
  • Bet­ter key­board sup­port, or at least one that's more use­ful for games
  • Fixed a bunch of bugs
  • Added col­li­sion de­tec­tion (did not make it to the video but it's there)

So let's go over the whole source code for that "game" and see how it work­s? Keep in mind that this code will look bizarre for your stan­dard Python pro­gram­mer be­cause it's de­lib­er­ate­ly done in a ... "ba­sic" style? Even in a BA­SIC style. Which means it aims to be more "struc­tured pro­gram­ming" than what you are used to see­ing.

Al­so, there are no guar­an­tees that any of the APIs ex­posed will even ex­ist to­mor­row, since this is still in a pro­to­typ­ing phase and things will change.

import time

load_sprite("player", "assets/PNG/playerShip3_orange.png")
x = 100
y = 500
step = 3
move_sprite("player", x, y)

We cre­at­ed the in­trepid play­er's ship, and put it "some­where". Sprites are iden­ti­fied by a name. All sprite op­er­a­tions will use that name to know what sprite should be af­fect­ed.

# A fleet of bad ships
fleet = [
    [f"enemy-1-{x}" for x in range(7)],
    [f"enemy-2-{x}" for x in range(7)],
    [f"enemy-3-{x}" for x in range(7)],
    [f"enemy-4-{x}" for x in range(7)],
]

for invader in fleet[0]:
    load_sprite(invader, "assets/PNG/Enemies/enemyBlack1.png")
for invader in fleet[1]:
    load_sprite(invader, "assets/PNG/Enemies/enemyBlue2.png")
for invader in fleet[2]:
    load_sprite(invader, "assets/PNG/Enemies/enemyGreen3.png")
for invader in fleet[3]:
    load_sprite(invader, "assets/PNG/Enemies/enemyRed4.png")

Again, just a few ships with dif­fer­ent look­s.


def move_fleet(x, y):
    """Move fleet so the left-top alien is in position x, y"""
    for inv_y, row in enumerate(fleet):
        for inv_x, invader in enumerate(row):
            move_sprite(invader, x + 90 * inv_x, y + 90 * inv_y)


fleet_x = 50
fleet_y = 50
fleet_step_x = 1
fleet_step_y = 5

A func­tion to move the fleet as a whole, and some in­fo about it, lo­ca­tion and speed.

load_sprite("laser", "assets/PNG/Lasers/laserBlue01.png")
load_sound("laser", "assets/Audio/laserRetro_004.ogg")
laser_last_shot = time.time()
laser_x = -100
laser_y = 0


def shoot():
    global laser_x, laser_y, x, y, laser_last_shot
    play_sound("laser")
    laser_x = x
    laser_y = y
    laser_last_shot = time.time()

Same for our lonely bullet, but we have a couple of new things. With load_sound we load into the program a sound (surprise!) and with play_sound it's played. Just like sprites, they are identified by name.

We keep track of when we shoot be­cause this is a ship, not a ma­chine­gun, Jim!

def check_hit():
    global laser_last_shot
    t1 = time.time()
    global laser_x
    for row in fleet:
        for invader in row:
            if check_collision("laser", invader):
                laser_x = -100
                laser_last_shot = 0

Col­li­sion de­tec­tion! If the bul­let hits an in­vad­er ... well, we can't make it ex­plode yet, but we move the bul­let out and al­low the us­er to shoot again, at least.

load_music_stream("background", "80616-lunchip.xm")
play_music_stream("background")

Just load and play a nice chip­tune! As usu­al, mu­sic is iden­ti­fied by a la­bel, so we can have more than one and play the one we wan­t.

def gameloop():
    global x, fleet_x, fleet_y, fleet_step_x, fleet_step_y, laser_y

The gameloop function is special. Whatever you put here CobraPy will try to run it 60 times a second. No faster, maybe slower if your gameloop takes too long. So this is where you do things like update the screen and interact with the user. You know ... a game loop.

    if is_pressed(114) and x < 720:  # right arrow
        x += step
    if is_pressed(113) and x > 0:  # left arrow
        x -= step
    if is_pressed(38): # a
        if time.time() - laser_last_shot > 1:
            shoot()

User interaction! Basically is_pressed takes a key identifier (nice constants coming soonish) and tells you if it's pressed or not. So, if right-arrow is pressed, increase x (within limits), if left-arrow is, decrease it (within limits). If "a" is pressed and you have not shot for a second, shoot.

    move_sprite("player", x, 500)

Well, that's why we in­creased / de­creased it, right?

    fleet_x += fleet_step_x
    move_fleet(fleet_x, fleet_y)
    if fleet_x < 50 or fleet_x > 150:
        fleet_step_x = -fleet_step_x
        fleet_y += fleet_step_y

The fleet moves to the right, then to the left, and at ev­ery turn, down. Does it re­mind you of any game you've seen?

    laser_y -= step
    move_sprite("laser", laser_x, laser_y)

Bul­let go up.

    check_hit()

En­e­my go boom. Even­tu­al­ly.

Audio! Navecitas!

Un­os min­u­tos eligien­do as­sets de ken­ney.n­l, un par de fun­ciones para que ten­ga so­porte de au­dio (sí, to­do el au­dio viene del código) ... ob­vi­a­mente no hay col­i­siones to­davía, y to­do es ... pre­cari­o.

El códi­go del jue­go: http://linkode.org/#E­Ja2EXWn­ToRI4zFr7vof15

The perfect Raspberry Pi setup

I am do­ing some semi-se­ri­ous Rasp­ber­ry Pi de­vel­op­men­t, so it was time I fig­ured out how to do it com­fort­ably.

My desk­top set­up is a two-­mon­i­tor con­fig­u­ra­tion, with my note­book on the ta­ble and a larg­er mon­i­tor above it. I like it, it's nice. The point­er nat­u­ral­ly goes from one screen to the oth­er in the ob­vi­ous way.

Desktop setup

Spe­cial­ly nice is that the lap­top's screen is touch and has an ac­tive pen, so I can use it nat­u­ral­ly.

But now, with the Rasp­ber­ry, I want to oc­ca­sion­al­ly show its dis­play. And that means switch­ing the mon­i­tor to it. Since I hate plug­ging and un­plug­ging things, I use one of the­se:

HDMI switch

It's a cheap tiny black plas­tic box that takes up to 5 HD­MI in­puts and switch­es be­tween them to its one out­put by click­ing a but­ton. It on­ly goes through the in­puts that have sig­nal, so since I on­ly have the lap­top's and the Pi's the but­ton tog­gles be­tween them.

If your mon­i­tor has more than one HD­MI in­put you can prob­a­bly just use that, but mine has just one.

But... what about key­board and mouse?

I could get a mul­ti­de­vice key­board and mouse, but I like the ones I have.

I could use a USB switch and tog­gle be­tween the two de­vices, but ... I don't have one.

So, I use bar­ri­er and con­fig­ure it in both the rasp­ber­ry pi and in the lap­top so that when my point­er goes "up" in­put goes to the Pi, and when it goes "down" in­put goes to the lap­top. That's ex­act­ly the same as with the du­al-dis­play se­tup, but with two com­put­er­s. Neat!

So, go ahead and con­fig­ure bar­ri­er. It's easy and there are tons of tu­to­ri­al­s.

Nex­t, make sure bar­ri­er starts when I lo­gin in­to both com­put­er­s. They way I pre­fer to do these things is us­ing sys­temd.

Put this in ~/.local/share/systemd/user/barrier.service in both machines:

[Unit]
Description=Barrier server
[Service]
Environment=DISPLAY=:0
Type=simple
TimeoutStartSec=0
ExecStart=/usr/bin/barrier
[Install]
WantedBy=default.target

Now you can make it start with systemctl --user start barrier or stop with systemctl --user stop barrier and make it start on every login with systemctl --user enable barrier

But while this is nice, it presents a prob­lem. When I am us­ing both dis­plays for the lap­top, I don't want bar­ri­er run­ning! Since I can't see the Pi's dis­play, it makes no sense.

So, I want to start bar­ri­er when the lap­top is us­ing one mon­i­tor, and stop it when it's us­ing two.

To do that, the trick is udev in the laptop. Put this (replacing my username with yours) in /etc/udev/rules.d/90-barrier.rules:

ACTION=="change", \
    KERNEL=="card0", \
    SUBSYSTEM=="drm", \
    ENV{DISPLAY}=":0", \
    ENV{XAUTHORITY}="/home/ralsina/.Xauthority", \
    ENV{XDG_RUNTIME_DIR}="/run/user/1000", \
    RUN+="/home/ralsina/bin/monitors-changed"

Basically that means "when there is a change in the configuration of the video card, run monitors-changed. Change the 1000 by your user ID, too.

The last piece of the puzzle is the monitors-changed script:

if `xrandr --listmonitors | grep -q HDMI`
then
    # The HDMI output is connected, stop barrier
    su ralsina -c '/usr/bin/systemctl stop --user barrier'
else
    # The Pi is using the monitor, start barrier
    su ralsina -c '/usr/bin/systemctl start --user barrier'
fi

And that's it!

This is the be­hav­iour now:

  • When the lap­­top is us­ing both dis­­­plays, they work nor­­mal­­ly in a "ex­­tend­ed dis­­­play" con­­fig­u­ra­­tion. They be­have like a sin­­gle large screen.

  • When I click on the HD­­MI switch and change the top dis­­­play to show the Pi's desk­­top, au­­to­­mat­i­­cal­­ly bar­ri­er starts in the lap­­top, and now the point­er and key­board change from one com­put­er to the oth­­er when the point­er moves from one mon­i­­tor to the nex­t.

  • If I click on the HD­­MI switch again, bar­ri­er stops on the lap­­top and I have a sin­­gle two-screen desk­­top again.

Ev­ery­thing be­haves per­fect­ly and I can switch be­tween com­put­ers by click­ing a but­ton.

Al­ter­na­tive­ly, we could start the bar­ri­er client when the rasp­ber­ry pi "get­s" the dis­play, and stops it when it goes away. The re­sult should be the same ex­cept for some cor­ner cas­es, but it has the added ben­e­fit of al­low­ing for a set­up with up to 5 de­vices :-)


Contents © 2000-2020 Roberto Alsina