sabato 29 aprile 2017

This is a simple script that takes all arguments on the command line and returns a list of directories for each argument.
I don't remember at all what the purpose of this was, probably something to process a set of directories via a batch starting from
a set of filenames.
By the way, let's say how baby I was at that time…

A lot less, uh?
It could be simpler, but so far I don't know any module to return the directory part of a path when a file is provided as argument, and
this is the reason I need to distinguish between the -f and -d cases.

The adoption of the list separator $" is specific to add the trailing backslash and to place every single directory on its own line. Of course this means, as $" suggests, that the array has to be printed via doubled quoted print. Here the adoption of say

or print is totally equivalent.

Let be honest here: the adoption of local and the surrounding block could be avoided, since the script exits implicitly right after
such couple of instructions, and this means the code could even be simpler, or better, shorter, but let's keep some good habits!

venerdì 14 aprile 2017

…I was assigned one of my very first program to develop: a way to assure an user can run no more than a specific number of instances
of the same executable.

The real story was this: a company was using an Unix ncurses based ERP, and users were forced to connect via remote shell and
launch it automatically. The problem was that several users were opening more terminals (and therefore ERP clients) limiting
resources to other users.

I wanted to demonstrate my skills being able to implement the solution in a couple of hours, and instead of spending time
searching for a production-ready solution on the Internet, I decided to do it all on my own.

It was clear to me I was needing a kind of wrapper to control the execution of external programs. In fact, since users were
automatically switched from the remote shell into the ERP client, it did suffice to place the wrapper as the
user shell.

But how to implement it? At that time I knew Java, C++, C, Perl and some Bourne Shell. Making it in Java was too heavy, and
most notably required to install a JVM on the server (it was the time of the Red Hat 5 branch). C and C++ required too much time
to come with a working solution, and Perl was the most promising allowing me to do everything I was able to do with
other languages, overcoming the limitation of the shell (e.g., arithmetic).

But at that time I was not a fluent Perl developer.

A few days ago I found the above program out of an old backup, and so I spent five minutes to read it again. Not surprisingly, I found
it awful with respect to the code I write today, and moreover I see a lot of code uglyness due to baby steps. But hey, it was fun
to see how many things I've changed in my coding style, idioms, adoption of the language and of its operators, and most notably
about how I'm today toward compact code instead of long and blown code. At that time I was convinced that as long the code was, as much
it must be simpler to read, today I believe it is the opposite (with a very few exceptions I tend not to adopt until I
can remember very well).

In this article I will dissect a few parts of the above program to show you how I was writing code back in those days, and it was
a huge time ago (at least in computer timeline): 15+ years ago.

2 Baby Steps

Well, as you can imagine when I started doing a real job I was nothing more than a programmer-to-be, and my knowlegde
about Perl was really tiny. I mean, I read the Camel Book (of course!), and I was experimenting with Perl as much as I could,
but I was not an avid consumer of the Perl community (as well as other communities) and so I did not have a lot of chances
to learn from other people experience and code.

More than that, I just finished my university degree, and so my mind was literally full of theories about writing
correct and beautiful code, but that were just theories without any implementation! And last but not least, I was convinced
I could do everything by my own (that is, who needs modules?).

Today I recognize the following as baby steps in the Perl world.

2.1 Method Prototypes

Yes, I was using prototypes everywhere.

Why? I suspect they were comfortable to me, since I was used to languages where each method has a prototype (C, C++, Java), and
so I was trying to use a kind of common approach to every language, applying to Perl prototypes even when I was not needing
them at all!

Of course, by time and experience, I found that prototypes are usually not useful at all in my programs, and made refactoring
a lot harder.

2.2 Method instead of Operators

Perl allows operators to be used without braces, but that was something my eyes were not able to parse!
Again, coming from languages where methods and operators both need parentheses, I tried to bend Perl to my will
and use operators the very same way.

2.3 Untrusting the Thruth

Perl has the great ability to cast a variable depending on the context, but it was something too much complex for me.
So for instances, instead of testing a scalar against a not-true value, I was using the defined operator:

# if ( $scalar )if ( defined $scalar ){ ... }

Worst: I was not using the ability of an array to be scalar-contextualized in tests:

#if ( ! @array )if ( not defined @array || $#array <= 0 ){ ... }

2.4 Global Variables

my what?

I was not using scoped variables, and the reasons were:

it was not clear to me the real difference between my and local, and I have to confess I thought local was what should be the
name for scoped variables (maybe because of the way some shells declare local variables), but since local was usually a bad idea
I decided not to use either;

my scripts were quite small and self contained, so there was no risk at all about variable clash.

2.5 Backtick as a Rescue!

I knew pretty much well a kind of command line Unix tools (e.g., grep, awk, sed, find), and sometimes I needed
to do something in Perl without knowing how to do but with shell tools. So, how could I merge the both?

Easy pal: backtick the Unix tools and manage the result in Perl!

2.6 No Modules, please

I was not using modules, both by design and by fear.

With by design I mean that I was writing scripts for machine loosely connected to the Internet (just think I was working with server behind an ISDN router!),
and therefore even dowloading a module and install it could be quite a pain.

By fear means I was quite scared about importing other people's code. I was still learning about how to use correctly the CPAN, how to read
the documentation, and so on. And I did not want to install things in the wrong way on code that must run. After all, I was half-an-hour
away from implementing some kind of module functionality by my own (ah, the ego…).

2.7 Regexp Sometimes…

I tried to use regexp, but I was too less experienced. Therefore I usually did the substitution with friendly tools, likesplit and alike.

I fear regexp nomore, and even if I'm not a master at all, I find interesting placing them in programs not only because
they allow me to write clear and compact code, but also because they still are some criptic stuff other developers
have hard time reading.

3 The Code

3.1 University Distortion

There are a couple of places where you can see evidence of the teachings at my university, most notably the
command line argument loop:

As you can see I was hardwiring the arguments directly into the program, as well as I was not using any getopt-like module.
That was by culture: university never told me there was a getopt way of getting parameters!

Please note also that I was checking the argument numbers as well as exiting from the program with a different exit code for each branch.
The style reminds pretty much the C-style I was used to work with during my exams.

3.2 Ready? Go!

How can I execute another program from within the Perl wrapper?

Well, the simplest way that I was aware of is to call execute, in other words, to work as a low level C:

3.3 How Many Instances can you Run?

Here I decided to take inspiration from the sudo policy file, and so I invented my own policy file with a pretty
simple syntax:

username@executable=instances

where:

username was the Unix username;

executable was the name of the executable to run;

instances was the number of the maximum allowed instances of the executable for the specified username.

And to make it looking mor eprofessional, I allowed the policy file to include a star in any field
in order to mean anything or any instance.

Of course, the above was full crap. For instance, if you were able to create a link from the executable to another
with the right name you could change you allowance. But luckily, no user was able to do that, and to some
extent even the other sysadmins!

Having defined the policy file syntax, reading the file was as simple as:

Instead of reading the policy file once (or seldom), I was reading it fully every time I needed to check an user; it was
a very non-optimzed code.
Moreover, I was reading and grepping it a line at time, a very keyboard effort.

3.4 How much are you Running?

How to get the number of runnable instances an user was running?

Piece of cake: let's do it in Unix, backtick in Perl and increase by one:

4 Lesson Learned

There is no lesson to learn here, but a lot of lessons learned in the between.

The only thing I could say is that you should never, never, throw away your code. Keep it, it is cheap, and someday you could
see how you progressed from a green programmer to the very guru developer you probably are today.

lunedì 10 aprile 2017

I read an interesting blog post on adopting open source at university as a way of teaching computer science, and I posted also a comment
on such article.
Here I would like to extend my point of view about the subject.
Having worked in an university for a few years, having done computer science at both sides of the desk, and having a quite good
experience in what became my day-to-day work, I believe I can express some opinion about.

Adopting open source as a teaching methodology should just be.
Period!
Instead of asking students to produce the same crappy software all over the time (a database layer, a GUI layer, a music store,
a calculator), put them on a real piece of software that someone in the world could use and adopt.
Why?

motivation: students will be happy to work on some real stuff with the main author(s) thanking them for their help, time,
and work;

learn something useful: real programs do things in the real world, and things in the real world must work, and work fast, and work
in accurate way. That is:

work on real data: nobody will ever notice your crappy homework do a full table scan each time you need to display one of your
fake music titles out of ten, but a real program will freeze once you try to do a full table scan just to display out a detail
out of a million records. This is something university cannot teach you, trust me!

deal with problems: university will teach you a lot of theory about using natural keys, algorithms to sort structures, avoid
data replication, and so on. Not always these approaches will drive you to a manageable software: learn to deal
with surrogate keys, duplicate data when it makes sense (e.g., network latency, historical reasons and so on).

learn the tools: developers around the world need to coordinate. Learn to use bug reports, stay on mailing lists, IRC channels,
and alike. Don't ask stackoverflow for someone to do your homework, learn how to find documentation and search for answers. Become
acquainted with revision control, compilers, linkers, and different platforms.

document for someone else: it is easy for you to explain what you have done to your teacher, in particular if you did it in the very
previous period of time (typically a semester). But can you document something so that another developer, even another student like
you, can understand one year later why and how you did a task?

do not start a project from scratch: typically the university cycle during semesters is something like design-implement-compile-run-explain-throw away_
and then you start over and over again every time you got an assignment, homework, or project. This is wrong! Real life does not work as such:
in real life you are often assigned to maintain or refactor an existing piece of code without having to throw it away.

learn idioms: developers around the globe are smarter than you. It is not they are more intelligent, it is just they are more expert
and know better the subject. Reading someone else (smarter) code is a great way to improve your knowledge and become smarter too. Learning idioms,
seeing patterns applied to real world code is a great start to become a professional coder.

fun: developers have their habits. They meet together in so called conferences, and usually got beers while talking about code, travel
around the world, and have a lot of fun. And even if you stay closed in your room, doing your homework, having a chat, a video call
or an email in your in-box with a "thank you" or "good job!" is really fun.

There are other reasons, but the above are my main choices to push students to the open source world.
So far, it seems that you are going to have only advantages and no drawbacks, but that's not true.
Becoming an open source contributor you are going to become smarter than your own university teacher, and this is a drawback so far as
the teacher signs your curriculum. It is something that is really hard for a teacher to keep in mind, but it is so true.
I was always saying to my student, in the very beginning of each class, that at the end they will know better than me the subject, and the reason
for that is that "I'm not going to spend whole nights studying before the exam!".
So, if you are a teacher, simply accept that.
Accept that a student could prove a better algorithm, or an idiom you don't know that works. Ask him for the details, learn from him.Learning is not a one-way process, with a god-like teacher and an idiot-like student; learning is a cooperation where someone expert provides the sparkle to someone else.
Would not be nice to see if both can grow during the path?

There is also another drawback: open source is not something you can teach without knowledge. You have to know the tools: revision control, IDEs,
bug tracking, issue tracking, wiki, testing and alike.
Most teachers urge teaching C pointers arhitmetic instead of basic tools, and that's not good.
Allow me to provide my very own example: I spent five years in a computer science degree, and nobody told me about revision control. While
doing my master thesis, being afraid of loosing some change or to mistakenly do a single line change (that will not blow up your project, right?),
I did my very own backup shell script that was running every hour to keep an historical copy of my work.
Shame on me, in the very same time I could have learnt rc or cvs (no, it was before git).

So my advice for students is be a part of an open source community, you will surely learn something that will make the difference in
your real job.
And my advice for teachers is accept smarter students and promote the adoption of an open source code base. There are a lot of "mini-hackers"
initiatives around the world (CPAN Pull Request, Hacktoberfest, etc.), pick one and try let your student do the rest.
You'll be happier, your student will be happier, the open source community will be happier and, who knows, your employer could also
become a partner in an open source community.