Declarative primitives or mkdir -p for the cloud

After some positive feedback regarding the concept of declarative primitives I would like to elaborate about it.

Defining declarative primitives

Declarative primitives is just a description of existing techniques. I gave it a name because I’m not aware of any other term describing these techniques. The idea behind declarative approach is to describe the desired state or result and not particular command or operations to achieve it.

Example: mkdir -p dir1/dir2/dir3

The outcome of the command does not depend on current state (whether the directory exists or not). You describe the desired state: directories dir1, dir2 and dir3 should exist after the command is run. Note that mkdir dir1/dir2/dir3 does not have the same effect: it fails if dir1 does not exist or dir2 does not exist or if dir3 exists.

The phrase declarative primitives emphasizes granularity. Existing declarative tools for the cloud operate on many described resources, build dependency graphs and run in order that they decide. Declarative primitives provide a very flexible way to control a single resource or a group of few resources of the same type. The flexibility comes from granularity. You decide how you combine the resources. You can easily integrate existing resources. You can modify just the properties of your interest on the resources you choose. This approach is ideal of scripting in my opinion.

Where are declarative primitives for the cloud?

sky-414198_640

I believe that when writing a script, using mkdir -p should be similar to using AwsElb(...).converge() for example. I’m working on implementing it (as a library for the Next Generation Shell) and I’m not aware of any other project that does it.

There are many projects for managing the cloud, how are they different?

Here are the solutions that I’m aware of and how familiar I am with each one:

  1. CloudFormation – using frequently (I prefer YAML syntax for it)
  2. Terraform – I’ve read the documentation and bits of source code
  3. Cloudify – familiar with the product, made modules for it
  4. Puppet – was using it intensively on few different projects
  5. Chef – was using it intensively in many projects
  6. Ansible – unfamiliar with this one (only took a look at documentation) so not reviewing it below
  • All take the declarative approach. You describe many resources or the entire system and feed the description to the tool which in turn does all the work. None of these solutions was designed to provide you with the primitives that could be easily used in your scripts. These tools just don’t match my view regarding scripting.
  • These tools can do a rollback on error for example. They can do that precisely because they have the description of the entire system or big parts of it. It will take some additional work to implement rolling back using declarative primitives. The question is whether you need the rollback functionality …
  • Some of these tools can be made to work with different clouds relatively easily. Working with different clouds easily may also possible with declarative primitives but the library I’m currently working on does not have such goal.
  • Except for Chef, the tools in the list above use formats or DSLs not based on real programming languages. [Update 2019-05-26: This means that except for trivial cases you will be using some additional tool to generate the descriptions of desired states. (Practice proved me wrong, this means convoluted/unclear definitions sometimes)] Limited DSLs do not work. See Puppet and Ansible [Update 2019-05-26: with release 0.12, Terraform too] that started with simple description languages and now they are almost real programming languages … which where never designed as programming languages, which has consequences.
  • I’m not aware of any option in the tools above that lets you view definitions of existing resources, which prevents you from starting managing existing resources with these tools and from cloning existing resources. I have started implementing the functionality that lets you generate the script that would build an existing resource: SomeResource(...).code() . This will allow easy modification or cloning.
  • A feature missing both from these tools and from my library is generating a code to start with for a given resource type (say security group or load balancer). Writing CloudFormation definition for a type with many properties is a nightmare. Nobody should start from scratch. Apache or Nginx configuration files are good example of starting points. Similar should be done for the cloud resources.
  • Note that Chef and Puppet were originally designed to manage servers. I don’t have any experience using them for managing the cloud but I can guess it would be less optimal than dedicated tools (the first three tools).

Scripting the cloud – time to do it right!

Bash – opinionated review

Pros

  1. Huge immediately available “library” of external commands, providing lots of out-of-the-box functionality. You don’t even need to “import” or “require” to get it.
  2. Easy manipulation of files and processes with good syntax for these tasks
  3. Pipes make combining programs very easy
  4. Always installed (OS X comes with version 3 for some reason, version 4 is easily installable).

The pros above make bash the best language for many system tasks (and not Ruby, Perl or Python for example).

Cons

  1. Horrible syntax for general purpose programming tasks (read anything that is not a process or file manipulation), probably consequence of bash not being designed as a programming language. Language features were added with time in a backwards compatible way. The syntax looks really bad.
  2. No nested data structures
  3. No exceptions
  4. No named function parameters
  5. Subshells are forks, preventing global variables changes to be visible outside of the subshell. Combined with very “interesting” rules of what is a subshell and what is not, this behaviour can be surprising.
  6. Default behaviour is not to exit if one of the commands returns an error (use set -e to change)
  7. Default behaviour is to treat unset variables as empty strings (use set -u to change)
  8. Behaviour switches with setAction at a distance anti-pattern
  9. Default prompt does not include critical information: exit code of the last command
  10. No semantic understanding of the output and hence no command line completion based on output of previous commands. What makes me angry the most, completing apt-get install HERE will use the whole available packages list, not the output of the apt-cache search ... you just used to find your package while most of the time completing based on the output would be the right thing.
  11. History includes the commands and sometimes timestamps but no relevant context such as working directory, relevant variables’ values, exit code, etc…
  12. Inconvenient programming

What’s being done about the numerous cons?

I don’t see much being done about these in bash. Backwards compatibility and the fear of potentially breaking huge amount of existing code is probably the reason.

There are alternative shells being/were developed. Unfortunately for compatibility and other reasons they don’t seem to address all of the cons. Some of this projects ruin the simple syntax for process and file manipulation by basing themselves on an existing general purpose programming language.

against-the-current-1356062_640

NGS, a new and completely different shell, does aim to fix all the cons while keeping the positive aspects of shell programming.

The bigger part of the language is already implemented. See how it looks like.

You are welcome to join the project.

Recommended tools – tmux

Project URL: https://tmux.github.io/

Tmux is a newer take on screen.

tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.

My usage pattern

And/or:

  1. Locally in one or more of terminal tabs. This keeps number of terminal tabs sane. I mostly use splits and occasionally tabs inside tmux.
  2. Remotely for avoiding multiple ssh connections, critical tasks, poor connection.

I’d recommend these navigation keys:

bind-key -n C-Left select-pane -L
bind-key -n C-Right select-pane -R
bind-key -n C-Up select-pane -U
bind-key -n C-Down select-pane -D

bind-key -n C-S-Left switch-client -p
bind-key -n C-S-Right switch-client -n
bind-key -n S-Left prev
bind-key -n S-Right next
bind-key -n M-j prev
bind-key -n M-k next
bind-key -n C-M-z resize-pane -Z

For a remote machine I suggest setting pane navigation keys to M-Left/Right/Up/Down. This way instead of hitting Ctrl+b C-Left or worse Ctrl+b Ctrl+b Left you just hit Alt+Left (aka Meta+Left).

Pros

  1. Zoom mode.
  2. Saner default prefix key Ctrl+b as opposed to screen’s Ctrl+a. Outside screen Ctrl+a usually jumps to beginning of a line and I use this shortcut frequently.
  3. Multiple copy buffers. See the prefix = shortcut in the manual.

Cons

  1. Mouse selection and scrolling behaves different than in plain terminal. The regular mouse selection can be done with Shift but still…
  2. I have not automated setting up remote machines’ tmux.conf automatically yet. That would be a huge win.

 

Recommended tools – VIM

Vim is a text editor. http://www.vim.org/

vim
GVim window with horizontal split, no tabs, using darkspectrum theme, viewing NGS project.

My usage pattern

GVim window. Using Vim in it’s own window as opposed to using it inside the terminal prevents unwanted interactions with terminal shortcuts. I use splits, occasionally tabs. Two :colorschemes I use, depending on the light conditions around me are default and darkspectrum (from vim-scripts Debian package).

Notable plugins

  1. CtrlP
  2. Fugitive
  3. Syntastic
  4. Tabular

Pros

  1. Very powerful editing commands – this works well with the dot (.) command for repetition.
  2. Highly customizable
  3. Can save and load the whole layout (open files, tabs, splits) to a file. See :mksession
  4. Supports C well, including showing the warnings and errors inside the editor after you save a file.
  5. Ability to record and play macros.
  6. Many useful plugins, including the one that displays the git branch. The the bottom right part of the screenshot.
  7. Remote files editing.

Cons

  1. Vim is not an IDE. Don’t expect features such as refactoring.
  2. I haven’t found the perfect mechanism for navigation between files in a project. The Ctrl-P plugin is somewhat helpful. :BufExplorer also helps. Still doesn’t feel 100% right.

Using Vim in a terminal with tmux

As I mentioned, I don’t usually use Vim this way but some people seem to be very happy to use the terminal+tmux+vim combo.

Nice video about using Vim with tmux: https://www.youtube.com/watch?v=5r6yzFEXajQ

Why not Emacs?

Vim and Emacs are the two best editors I’ve seen. I don’t think either one is better. They are just very different. I have tried Emacs several times. Last time lasted several months. Each time it just did not feel right for me.

Bashing bash – unexceptional

This is the third post in the “bashing bash” series. The aim of the series is to highlight problems in bash and convince systems and software engineers to help building a better alternative.

The problem

What is the output of the following script?

#!/bin/bash

set -eu

echo Here
false
echo Not here

Right, the output is

Here

Imagine that instead of false you have a lot of code. Since there are no exceptions, you have no idea where the error occurred.

inspector-160143_640

Solutions using bash:

  1. Use set -x to trace the code.
  2. Add echo something every here and there to know between which two echo‘s the error occurred.
  3. Catch the error using trap and print the line number as suggested on StackOverflow . Writing this additional catching snippet at the top of every script is not really convenient.

This problem of unclear error location is unimaginable in any normal programming language.

“There is no problem, just don’t do it”

Bash was not intended to be a “normal” programming language. Some people say it’s an abuse of bash to use it as such. Looking at the code written in Bash I can tell it really is an abuse in many cases.

The reality though is that bash is still (ab)used for programming. In some cases Bash has positive aspects which outweigh the need to use other languages. In other cases a program starts as a small Bash script and is just not rewritten in another language after the script grows.

I suggest making a better shell rather than convincing people not to abuse Bash. People will keep on doing what they are doing. Let’s make their lives easier by providing them with a better shell.

The suggested solution

Use NGS. In NGS, any failed process throws an exception. Let’s take a look at the script below

#!/usr/bin/env ngs
echo Here
false
echo Not here

What’s the output?

Here
Not here

WAT?

Well, actually false returning an exit code of 1 is not an exception, it’s normal. If any command returning non-zero code would cause an exception, you wouldn’t be able to write for example if $(test -e myfile) do_something .

Failed process is a process that returns an unexpected exit code. Here is the part of stdlib that defines what’s a fail and what’s not:

F finished_ok(p:Process) p.exit_code == 0

F finished_ok(p:Process) {
    guard p.executable.path == '/bin/false'
    p.exit_code == 1
}

F finished_ok(p:Process) {
    guard p.executable.path == '/usr/bin/test'
    p.exit_code in [0, 1]
}

Such definitions also mean that you can easily extend NGS to work properly with any other command, simply by adding another finished_ok function. (Or add it to stdlib if it’s a common command so everyone would benefit).

So where are the exceptions?

We’ll have to modify the code to get an unexpected exit code. Example:

#!/usr/bin/env ngs
echo Here
ls nosuchfile
echo Not here

Output:

Here
ls: cannot access 'nosuchfile': No such file or directory
========= Uncaught exception of type 'ProcessFailed' =========
====== Exception of type 'ProcessFailed' ======
=== [ backtrace ] ===
[Frame #0] /etc/ngs/bootstrap.ngs:158:1 - 158:10 [in <anonymous>]
[Frame #1] /etc/ngs/bootstrap.ngs:154:17 - 154:29 [in bootstrap]
[Frame #2] ./2.ngs:3:4 - 3:14 [in <anonymous>]
[Frame #3] /usr/share/ngs/stdlib.ngs:1116:11 - 1116:15 [in $()]
[Frame #4] /usr/share/ngs/stdlib.ngs:1050:29 - 1050:42 [in wait]
[Frame #5] /usr/share/ngs/stdlib.ngs:1006:7 - 1006:20 [in ProcessFailed]
=== [ dump process ] ===
(a lot of not very well formatted output with info about the process)

Please help building a better alternative

Go to https://github.com/ilyash/ngs/ and contribute some code.

Small intro to threads, race conditions and locking

embroidery-987866_640

Programming with threads has some pitfalls. This post deals with the basic problem with concurrent code execution – race conditions.

Definitions

Code – part of a program

Threads – code executing in parallel (concurrently) with other code

Race condition (in our context) – several threads running in parallel and their overall result depends on the scheduling of the threads.

The problem

Below is a very small naive code that demonstrates the problem.

We have a global variable i which is incremented by several threads (which run concurrently). The code for incrementing i is i = i + 1 . Multiple threads executing the code below have a race condition. One would think that 100 threads doing such increment 100 times each would result i being 10000 at the end.

Incorrect code

THREADS = 100
ITERATIONS = 100

i=0
THREADS.ptimes(F() {
    for(j;ITERATIONS)
        i=i+1
})
echo(i)

Incorrect code explanation

The code is in the NGS language but the logic would be the same across many languages that have the same concurrency model: C, Java, etc.

Side note (skip freely):

This example would not apply to some languages which guarantee atomic variable increment. There would be no problem there. If we change the computation to something more complex, even in these languages we’re back to code similar to the above.

ptimes – “parallel times” function – runs the given code in parallel threads.

N.ptimes(code) – runs N threads executing code.

F() { ... } – literal function

for(j;N) – loops with values of j from zero to N (not including N). Sugar for for(j=0; j<N; j=j+1).

Code summary: in 100 parallel threads do i = i + 1 100 times in each thread.

Incorrect code output

The scheduling of the threads is done by the operating system. Since the scheduling is out of our control, the result is unpredictable when a race condition is present.

The output is actually about somewhere between 7900 and 8400 on my system, different each time I run this code, not the 10000 you might expect.

So, why the result of i = i + 1 is dependent on scheduling of the threads? Let’s examine the two following scheduling alternatives:

Incorrect code threads scheduling alternatives

Scheduling alternative A:

Thread 1 runs all the code (i = i + 1), then thread 2 runs all the code. No problem there. i would be incremented by 2.

Scheduling alternative B:

Thread 1 runs i + 1 : fetch the value of i and add one to it. Thread 2 also runs i + 1. Thread 1 saves the computed value of i + 1 to i. Then thread 2 does the same. The problem is that the fetched value of i was the same for both threads. Summary: both threads fetched the same value of i , incremented it and stored. Total increment of i is one.

Since scheduling A vs B have different outcomes, it’s a race condition, the output is unpredictable and sometimes incorrect. The incorrect code above is purposely such that the output is mostly incorrect.

Fixing the code

Add l = Lock() at the beginning of the code.

Replace i = i + 1 with l.acquire(F() i=i+1) .

Code explanation

Lock() – creates a new lock

l.acquire(code) – acquires the lock l, runs the code and releases the lock.

Locks

Locks provide a way to make sure that only one thread executes the given section of a code. In our case, using the lock allows only “Scheduling alternative A”.

When several threads try to acquire a lock simultaneously, only one will succeed and then enter the code. When this thread finishes executing the given code it releases the lock. After the lock is released, it can be acquired by another thread.

Any locking mechanism must be based on an atomic hardware operation such as Test-and-set or Compare-and-swap. Trying to come up with your implementation of a lock which is based on code only will not work, you will be shifting the race condition from one place to another.

Summary

Watch out for race conditions as they are a common problem when using threads. Use locks to avoid race conditions. For best performance the code which is run when holding a lock should be as small as possible.

See also:

  1. Concurrent data structures
  2. Message Passing Concurrency / Message passing
  3. Event Loop Concurrency

Full incorrect and correct code: https://github.com/ilyash/ngs/blob/6add46e6f60ce398f37f5138ece16cf8fdfd719b/c/demo/locks.ngs

Tips for beginning systems and software engineers

notes-macbook-study-conference

From time to time I’m toying with the idea to give a lecture to newcomers in the  IT industry (systems or software engineers). Here are some of the points that I would include in it:

Human factor

Bugs

Software bugs are inevitable. Just accept it. Thinking that you will get any significant piece of code right the first time is statistically wrong. The correct assumption is that bugs will be there, various kinds of bugs. The answer to this problem is the correct development process. The process should include:

  1. Automated tests – minimize chance of bugs getting into the production environment. There will be bugs not covered by tests. Production environment usually differs in some ways from the testing environment. This means some bugs will make their way to the production environment so monitoring is needed. Automated tests help combat the following problems:
    1. Slower development because one becomes hesitant to make changes and has to test manually.
    2. More bugs as manual tests are not as good.
    3. Bad code as it will less likely be refactored.
  2. Gradual deployment of new versions.
  3. Monitoring – detect errors/bugs in running software. Goes well with gradual deployment.
  4. Metrics – detect performance issues and errors  in running code.
  5. Automated healing / rollback – tricky technique, use it carefully. Example: the system detects that the last deployed version of the application causes increased latency (or error rate) and automatically rolls back to a previous known-good version.

The aim of the correct process is to minimize the number of bugs that reach the production environment and minimize duration and effect of presence of such bugs in production.

Ready-made solution pitfall

You will read articles and blog posts that state that problem P has S as best solution.  Your circumstances may seem similar to what other people engage with but in reality they are unique just for your situation. Think twice before deciding that the problem P is exactly the problem you are solving and whether the solution S is applicable and is best for your situation.

Related: see Hypes section below.

Ease vs simplicity confusion

Simple: a line of code that does something very small and specific.

Easy: a line of code that does a lot by calling a framework function causing thousands of lines of code to be executed.

See also: https://www.infoq.com/presentations/Simple-Made-Easy

Hypes

The IT industry is very hype-prone. Companies develop products for the industry. The bigger the budget, the more hype will be created around such product in order to sell or cause adoption. Even when the company provides you with a product that is free, the company may very well still profit in some indirect way so there is still a commercial interest. Remember that such hypes have nothing to do with how good the product is and especially how well it fits as a solution to a specific problem at hand. Note that advertisements usually do not include a “not for” section.

Detecting a product hype: it’s “cool”, it’s all over the news sites and blogs, the impression is that everyone uses it already and you are a laggard which does not understand how cool it is.

Detecting a product you might want to use: your friends that use the product tell you it’s good or it’s the best alternative and/or it matches the criteria you thought of before searching for the product.

Quoting Avishai Ish-Shalom:

Here’s how I recognise hypsters and hyped technology:
“it solves everything! it has no disadvantages!”
Here’s how I recognise experience and serious technology:
“it’s good for X but can also do Y to a degree, but beware of T, Z”

See also: Prove your tool is the right choice

Related: http://www.gartner.com/technology/research/methodologies/hype-cycle.jsp

Be a skeptic

When considering doing a task, assume the following (unrelated to each other) aspects:

  1. Your task will take more time and effort than you estimated.
  2. The resulting code will make the system much more complex and will be a nightmare to maintain.
  3. The feature will rarely or never be used. That is often the case.

Professionals usually avoid doing tasks which are “nice to have” and are not really required. Being a skeptic usually has almost no penalty when you are wrong but can save a lot of time and effort when you are right.

Code

Code duplication

Don’t duplicate code (copy+paste):

  1. Duplicated code means more maintenance.
  2. Duplicated code may some day be updated in one place and not the other, causing bugs.
  3. You will be looked down upon by senior developers as this is a big no-no.
  4. This rule has rare exceptions, use your judgment. If not sure, don’t duplicate.

Code reuse

Do it. When using any existing code whether it’s a function, program, utility, library or framework – take the time to read the documentation first. Understand the functionality, limitations, architecture. It is a very good investment of your time. You can learn it the hard way after several times when you discover that the particular code is not what you need. Such mismatch usually needs either a work around or picking another library, function or tool.

Code style

Pick one style and stick to it. In cases when a project has few styling conventions for some reason, the local convention wins. Example: all files use tabs except the file that you are editing, which uses spaces. In this case use spaces. Inconsistent code style causes higher maintenance costs and developers’ frustration.

See also: https://en.wikipedia.org/wiki/Programming_style

System complexity and code complexity

Strive for simplicity. More complex systems:

  1. Are harder to maintain
  2. Are harder to add new code to
  3. Have more bugs
  4. Have bugs that are harder to find

Complex and complicated are different things. The system or code might need to be complex when solving a complex problem. Complication is an unnecessary byproduct of bad software architecture, bad design or bad implementation. The more professional the programmer is the simpler and cleaner the produced code gets.

Automation

Benefits of automation are:

  1. Avoiding boring repetitive tasks
  2. Minimizing chances of mistakes (common in manual tasks)
  3. Describing the task for your future self and others
  4. Allowing others to do the task easily
  5. Increased productivity

Important defaults

Here are important defaults the can save you many tears. Deviation from these requires justification.

  1. UTF-8 for character encoding
  2. For servers: UTC time zone

Knowledge and proficiency

Theoretical knowledge

A must:

  1. Big O notation.
  2. Common data structures and how they are implemented.
  3. Common algorithms and their time and space complexity.
  4. What a CPU does, which opcodes exist for a CPU of your choice.
  5. Compilers and compilation.
  6. Interpreters.
  7. What a kernel does, and it’s main system calls.

Practical knowledge

A must:

  1. Learn at least 3 very different programming languages. I’d suggest C, Lisp and Python. The chances are that you will not find a Lisp job but it surely will make you a better programmer.
  2. How the Internet works: IP, UDP, TCP, Routing, BGP, NAT, DNS, HTTP, HTTPS, SMTP, load balancing, browser. Pick one of the above and read an RFC that describes it.
  3. Cloud concepts

Nice to have:

  1. HTML / Javascript (reading the spec would be very nice)
  2. Character encodings and UTF-8 in particular

Tools

Become proficient with your tools if you want to be professional (read: work smarter and faster and be paid more). Imagine that you edit a text for just a few hours a day as part of your job. Invest a few days to learn more editor commands in order to become 10 or 20 percent more productive. This pays off quickly. Continue smart investment of your time by learning bits that will help you the most.

Programming languages are among the tools you will be using. One of the best investments of your time would be a deeper understanding of the language, and it’s tools.

Never stop learning! Among other benefits, this should improve your learning skills. This is one of the important skills you need to do your job.


See also: discussion about this post on Hacker News.

That was my opinion. Would you add any other points?

Bashing bash – undefined variables

This is the second post in the “bashing bash” series. The aim of the series is to highlight problems in bash and convince systems and software engineers to help building a better alternative.

The problem

What does the following command do?

rm -rf $mydir/

Looks like the author would like to delete $mydir directory and everything in it. Actually it may do unexpected things because of missing quotes. The rant about quotes is in the previous post. This post is about yet another issue.

The correct commands should be:

set -u
...
rm -rf "$mydir/"

The important thing here is set -u . Without it, when $mydir is undefined for some reason, such as a bug in code preceding the rm command, there is a chance to brick the machine because an undefined variable becomes an empty string so the command is silently expanded to

rm -rf /

800px-Brick

While more experienced engineers will usually use set -eu at the beginning of the script, omitting this declaration is a big trap for others.

Side note. You could ask why the original command has a trailing slash. The trailing slash is common and is used to signify a directory. While to the best of my knowledge the rm should work the same without the slash, some commands are actually more correct with trailing slash. For example cp myfile mydir/ would copy the file into the directory if it exists and would cause error if it doesn’t. On the other hand,  cp myfile mydir would behave the same if directory exists but would create a mydir file if there is no such directory nor file, which was not intended. Other commands such as rsync also behave differently with and without the slash. So it is common to use the slash.

See also: http://www.tldp.org/LDP/abs/html/options.html – bash options

The suggested solution

In NGS, any use of an undefined variable is an exception.

ngs -e 'echo(a)'

It’s going to look prettier but even in current implementation you have all the information about what happened:

========= Uncaught exception of type 'GlobalNotFound' =========
====== Exception of type 'GlobalNotFound' ======
=== [ dump name ] ===
* string(len=1) a
=== [ dump index ] ===
* int 321
=== [ backtrace ] ===
[Frame #0] /etc/ngs/bootstrap.ngs:156:1 - 156:10 [in <anonymous>]
[Frame #1] /etc/ngs/bootstrap.ngs:152:17 - 152:29 [in bootstrap]
[Frame #2] <command line -e switch>:1:8 - 1:9 [in <anonymous>]
...

While bash options probably have historical justification, a new language should not have such a mechanism. It complicates things a lot. In addition, the programmer should always be aware what are the current options.

Please help building a better alternative

Go to https://github.com/ilyash/ngs/ and contribute some code.

Bashing bash – variable substitution

This is the first post in the “bashing bash” series to highlight problems in bash and convince systems and software engineers to help building a better alternative.

Bash is a very powerful and useful tool, doing a better job than many other shells and programming languages when used for the intended tasks. Still, it’s hard to believe that writing a software decades later can not be done better.

The problem

What does the following command do?

cp $src_file $dst_file

One might think it copies the given file to the specified destination. Looking at the code we can say it was the intention. What would actually happen? It can not be known from the line above. Each $src_file and $dst_file expand to zero to N arguments so unexpected things that could happen. The correct command would be

cp "$src_file" "$dst_file"

Forgetting the quotes or leaving them out assuming  $src_file and $dst_file will always contain one bash word, expanding to exactly one argument each is dangerous.

Keeping quoting everything makes code cluttered.

The suggested solution

In NGS, $var expands to exactly one argument similar to "$var" in bash. The new syntax $*var, consistent with similar syntax in other NGS parts, would expand to zero to N arguments.

Please help building a better alternative

Go to https://github.com/ilyash/ngs/ and contribute some code.

Common Sense Movement – where is it?

brain-605603_960_720

Let’s look at systems and software engineering.

We hear about all kinds of “cool” methodologies, ideas, frameworks: DevOps, Scrum, Agile, Kanban, Continuous Integration, Continuous Delivery, Puppet, Chef, Ansible … and combinations of these.

Why do you hear about all this cool stuff all the time? Why there are hypes all the time? Simple: money. Another hype, another opportunity to sell you something [at higher price]: products, support, certifications, guidance. You don’t necessarily need these things but they definitely would like to sell you all of it.

I’m starting Common Sense Movement

This humorous thought crossed my mind yesterday. You know, just to balance the situation a bit. Then I realized why don’t you hear much about the shiny cool “common sense” methodology: money.

You can’t sell a “common sense” certificate. That’s because if someone really has some common sense, he/she is not going to pay you for this crap and the only certificate you can sell would be “Failed Common Sense Practitioner”. Actually I doubt you can  hardly sell any crap to common sense practitioners. That’s a problem. So, there is no Common Sense Movement for you 😦

I really would like the hype waves to stop so we could just do our work in peace. Meanwhile, when you are approached by a client or a boss with yet another “We need tool X” or “We need technology Y” you should really answer with “Prove that you need it and it’s optimal usage for our money and time considering other alternatives” no matter how new,shiny or cool that thing is.