Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Publicaciones sobre programming (publicaciones antiguas, página 90)


Una her­ramien­ta con un po­ten­cial gi­gan­tesco ... que no fun­ciona.

Acom­páñen­me en un paseo por la frus­tración.

UP­DATE: Al pare­cer el prob­le­ma es SÓ­LO EN MI SIS­TEMA!

Así que hay un tema in­tere­sante para de­buguear por lo menos.

UP­DATE 2: El prob­le­ma es kit­ty, el em­u­lador de ter­mi­nal que es­toy us­an­do!

Ep 47: Review Streaming Deck de Space Legends

Me crucé en twit­ter con este pro­duc­to, un stream­ing deck "bara­to" he­cho con im­pre­sión 3D y me di­je, hey, eso parece co­pado!

Así que acá es­toy 20 min­u­tos hablan­do de es­o. Y comien­do pastafro­l­a.

Este video NO fue spon­sore­ad­o, yo PAGUÉ ese stream­ing deck, así que será una opinión bue­na o mala, pero es la mía.

Space Leg­end­s:

  • http­s://­sta­gram.­com/s­pacele­gend­sok/
  • http­s://twit­ter.­com/Le­gendsS­pace


  • Músi­ca: http­s://www.ben­sound.­com
  • Tí­tu­los: http­s://flex­clip.­com
  • Ed­i­ta­do us­an­do: kden­live
  • Pastafro­l­a: El Moli­no (San Isidro)

Own your data: mirroring your Github

Yes, you SHOULD own your da­ta. Specif­i­cal­ly, if you are cod­ing some­thing, you should own it. And I don't mean own­ing in the sense of "I have the copy­right" be­cause sure, you al­ready do. There are thou­sands of lines of code I wrote in the 90s and 2000s of which there is no ex­tant copy. NONE. Weeks and months of code, all gone, for­ev­er.

I mean own in the sense of HAV­ING A COPY OF IT. You should have a copy of your code.

No, hav­ing it up in GitHub is not the same as hav­ing a copy, be­cause you may lose the ac­count (seen it hap­pen) or delete the re­po (done it ac­ci­den­tal­ly) or they may just delete it for what­ev­er rea­son (it hap­pens)

No, having it up in GitHub and having a git clone in your machine is not enough, because you are not going to pull every day, and checkout every branch.

No, us­ing Git­Lab in­stead or in ad­di­tion to GitHub is not the same as own­ing a copy.

So, how do you own a copy?

You set­up your own pri­vate GitHub-­like-thingie.

My favourite one is Gitea ... it does 80% of what GitHub does, for free, from a sin­gle self­-­con­tained bi­na­ry and it runs just fine in a Rasp­ber­ry Pi 3.

It has a fea­ture to clone a GH re­po. It will pe­ri­od­i­cal­ly clone all the branch­es, and keep them up to date. You can then con­tin­ue to work as usu­al and it will do its thing in the back­ground, unat­tend­ed.

Or you can use it as source of truth and make GH the mir­ror. Your choice.

So, what's left? Mak­ing a copy of all your GH re­pos.

Turns out there is a nice script to do that: http­s://github.­com/­jaedle/mir­ror-­to-gitea

You will need:

  • Gitea run­ning some­where with some free disk space
  • Dock­er run­ning some­where
  • Gen­er­ate a app to­ken in Gitea
  • Fol­low sim­ple in­struc­tions (it's one com­mand)
  • Wait from a few min­utes to a few hours, de­pend­ing on how much you are mir­ror­ing.

And voilá.

Soft skill: naming things


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.


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­

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
    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")

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:

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.


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

Contents © 2000-2023 Roberto Alsina