Posts mit dem Label Python werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Python werden angezeigt. Alle Posts anzeigen

Sonntag, 26. Februar 2017

Poor Man's Microservice Configuration Using Environment Variables

tl;dr: This post shows a simple and tech stack neutral way to provide a configuration file for a microservice.

These days a common approach to microservice deployment is to ship them as a standalone binary package. The Uber Jars in the Java world are a prominent example. This simplifies operations - particularly when you are in a pre-Docker environment.
All it needs to run a microservice is a single Linux command line. As an old Linux guy I am delighted with this "back to the basics" approach.

A must-have feature for those kind of processes is the ability to configure the service via an external configuration file. Here, you often find the usual suspects like YAML, JSON or even INI.

This advice of the 12 factor manifesto made along existing config option more prominent again: good old environment variables.

This post shows a demo microservice which consists of three files:

  • demoservice-starter.sh - starts demoservice.py and provides it with its configuration
  • demoservice.cfg - the configuration file for this service consisting of shell variable definitions
  • demoservice.py - the actual microservice (just a modified Flask "Hello World")

The service is started like this:
$ ./demoservice-starter.sh demoservice.cfg &

Outside to inside explaination:


demoservice-starter.sh 


Line 6 reads in the config file provided as command line argument. Technically the content of demoservice.cfg is parsed and executed.

Remarkable here is that the environment variables created in line 6 are just visible for demoservice-starter.sh and its children but not for the rest of the Linux system. In contrast to a user or system "profile" file containing global environment variables this is a decentral, scoped approach to provide environment variables.

Line 7 then starts the microservice. In this case I use Gunicorn as server for my little Flask application. I use "&" to send the gunicorn process to the background and continue the script execution.

Line 8 stores the process id of my just started process. This PID variable is needed two times. On line 9 we enter a "wait" state until the gunicorn process exits. This is basically a more sophisticated version of an endless sleep loop. The latter one works as well but it requires more code ;)

To stop the microservice we just kill demoservice-starter.sh. However, the shell does not kill our gunicorn child process automatically.

To retrofit this behaviour we have to quickly discuss what kill actually does. This is what the man page says:

kill - send a signal to a process. The default signal for kill is TERM.

So when we kill demoservice-starter.sh we actually just send the TERM signal to the script. What we need to do now is to forward this signal to our child gunicorn process.

This is what line 4 does: When the script receives a TERM signal it kills the gunicorn process which then lets our "wait" command continue to the end of the script.

A quick note on line 2: Here we enable two features of the bash shell. "-a" automatically makes variables defined in the script available for child processes. Without "-a" we would need to prepend each variable in demoservice.cfg with a "export" statement.

The other feature is "stop script on error" by using "-e". This is very useful also for build scripts to safe yourself from each time manually checking exit codes.


demoservice.py

There is not much to say here. When the route path "/" of our demo service is accessed via HTTP GET we use Pythons "os.getenv" function to read the content of the environment variables and echo their content. Remarkable here is the usage of Pythons Literal String Interpolation on line 10 which was introduced in version 3.6.

Sonntag, 11. Januar 2015

A software engineer does for a dime what any fool can do for a dollar - SICP Finished

Done! Done! Really, no kidding. It took longer than expected but eventually I'm done with my self study of the online material of Computer Science 61A, Spring 2014 edition. The course is a modernized version of the material in "Structure And Interpretation Of Computer Programs" (SICP).

For more informations on why I initially started the course see my post from March 2014.

This post is about my lessons learned, findings and experiences.

General Software Engineering Findings

A great quote from the lecture (for a geek T-shirt maybe?): A software engineer does for a dime what any fool can do for a dollar.  The key to such an efficiency is abstraction and separation of concerns.

This wasn't knew to me but it was good to see that those concepts were not invented by the "object-oriented people". They've made the idea popular but you also can achieve nice abstraction layers in your code by only using functional programing, see this section of the original SICP book for a good example.

Recursive Thinking

Before I started the course I probably never wrote a recursion - at least not by intention. In SICP recursion is an important concept and I had solve many different exercises on that topic. Over time I believe I can say I've adopted the recursive thinking.

The most important idea here is the leap of faith. This is a way of thinking which help dealing with recursion: Since it is hard to play a whole recursion through in your head (particularly for complicated tasks) develop your code with a simpler variant of the original problem in mind and believe that the recursion will also work for the more complex variants.

Read Eval Print Loop (REPL)

These days I wouldn't start a bigger programing project without having a REPL available. A REPL gives you an interactive way to try out some pieces of code before adding it to your actual program.

Ideally you can interact with your programming language line by line - like in Python: Type in python and you're inside the REPL where your can program interactively. For Javascript on the server side node.js offers something very similar. For client side Javascript just use the console of the browsers development mode (F12).

For Java I utilize the Eclipse Scrapbook, for C I sometimes use codepad.org. Those last two examples are no REPLs since they are not interactive but at least they provide some convenient way to try out code. For C I might use straight gdb next time - we'll see how well that goes.

Functional Programming

SICP is heavily relying on the power of higher order functions. That is due to the Scheme heritage of the course material. In the original SICP book (the wizard book) the possibility to assign values to a variable is mentioned somewhen in the middle of the book. This modern version of the course is not as puristic.

The further you work your way through the course material you see functional programming being used side by side with classic procedural and object oriented programming. In my opinion this is what makes Python such an interesting language: you pick the programing paradigm (the tool) which fits best for the job to be done.

I did some Javascript coding recently and used this occasion to re-read Eloquent Javascript. After having taking SICP this whole fuzz about Javascript functions is now much less confusing. The syntax could be more elegant though ;-)

Object Oriented Programing

Due to my efforts in structuring my work code I was aware of Abstract Data Types (ADT) before. In the course we've pushed this idea further: We've been using Python to implement an own object model including inheritance. This object model stood beside the build-in OO-features of Python.

This was an impressive and eye opening experience. Now I eventually know how to give the bash OO-capabilities ;-)

To quote the teacher, Professor Hillfinger: Object oriented programing is just a disciplined way to structure your programs.

Declarative Programing

The last quarter of the course had a huge emphasis on declarative programing. We've learned the concept, discussed a simple interpreter of a small invented declarative language written in Python. This language was a mix of Prolog (the structure) and Scheme (the brackets).

I saw that this is a very different way to approach solving a problem and that you should be aware of it. However, for my taste we've spend too much time on coding exercises with this little academic teaching.

Python as The Courses Main Language Language

Many years back my first programing language was Perl which impressed me with the power of a couple of code lines. Python is for me Perl done right - a multi purpose high-level scripting language with an easy to read syntax. At least Python doesn't share Perl (bad) reputation for cryptic one-liners.

Writing some Java after having done Python makes me feel like "Is the handbrake still pulled?" - not to mention my emotions going from Python back to application programing in C.

Scheme - Your Fathers Brackets

The original material of the course was entirely held in Scheme. In the new version the main programming language was Python but Scheme was still very present.

After doing some Scheme syntax and coding exercises the last project was about writing an own Scheme interpreter in Python. I wouldn't say that I'm now an expert in designing programming language but if I would ever get the task to implement an own language I definitely have a clear idea of the basic concept - a constant (meaning recursive) evaluation and application of a stream of input tokens.

This concept is so fundamental that it made it on the originals book title:
Quelle: http://icampus.mit.edu/files/2011/12/xTutor1.jpg
I have to say that I haven't become a big Lisp/ Scheme enthusiast. I still found the syntax rather confusing. However, I can image that it could be fun coding a bigger project and thus spending more time with the language..

Time Management

I started the course when I was off on parental leave for two months. At the beginning of that time I appointed one full day per week for the course work, in the second month I increased to two days per week. Additionally, I was watching the lecture screencasts in the evenings at home.

To stay focused I tried to study at my local universities library as often as I could.

When I started working again things slowed down. I tried to shift my study time to the evenings but my performance is not the best after 8:30 pm, particularly when you're not "just coding" but trying to solve tricky lab tasks. Additionally, work (a lot of mighty C programming) was quite involving.

The trick was to believe in small steps and to celebrate every complete homework, discussion or lab assignment.

At the beginning I tried to do all homework tasks, also the extra credits. When I saw my pace going down I decided to be just an average student and to focus only the compulsory work. My pace increased again and I realized that to be average in my situation was a good decision. It was my trade off being a full time worker, committed family father and a remote student at the same time.

Self Paced Learning

The course wasn't designed as a self study course. However, the lecture screencasts where great, I watched them all, some of them more than once. I found out that my brain digests new ideas better if new material is first presented/ explained to me and then I start practicing on my own.

The study guide Composing Programs also helped a lot to approach a topic from a second side (first listen to the screencast, second read in the book).

When we've learned about environment diagrams, the Online Python Tutor was very helpful.  It's basically a graphical debugger for smaller code snippets which nicely illustrates the environment frames involved  and their content.

Most of the hands-on assignments (labs, homework, projects) came with unit tests which described the intended behaviour of the functionality to be implemented. This way I could always check my implementation. Solutions were also available (with the exception of the projects).

Maybe the biggest problem for me was the lack of support from somebody else. As an enrolled student there are assigned teaching assistants (TAs) to help you. If I had questions I only had the Google search on my side which wasn't always as effective.

Particularly when I got into writing recursive functions I was sometimes fighting for hours to finish a task. Of course I only could have looked up the solution but this wasn't my intent - the whole purpose of my studies was to deeply understand the material.

Bigger projects where intended to be work on by small teams. As a one man team I did all the tasks on my own. This was also one reason why I took my longer then planned to finish the course.

Next Steps And Follow Up Courses

Online courses are great. They have their limitation once you get into project or group work. But e.g for learning a new programming language or library sites like codeschool.com are nowdays first choice for me. Infact, I would rather take a week off and work my self through a quality online course than attending a real life training. Check out this AngularJS course as an example for what I mean.

I was a bit disappointed that CS169.1x had already started when I finished: CS169.1x teaches the fundamentals of software engineering using Agile techniques to develop Software as a Service using Ruby on Rails. They have now the archived material available so I might work my self through that course again - we'll see.

Conclusion

It was fun and I definitely would do it again. Also for me the modern Python version of the course was more appealing than the pure text book based study of the old Scheme book.

Sonntag, 2. November 2014

Reflections on SICP (Part 1) - Function dispatching in C

Yesterday I've committed the last work for the Scheme project of SICP. Work, namely a lot of mighty C coding is mainly responsible for not having finished the course yet. However, since I am in the last quarter of the course material I decided to recap from time to time - what are the things I've learned, what was good, what was surprising and so on.

One of my favorite learnings is the idea of a dispatch table. Instead of having a long list of if/elseif branches which direct to a certain function the idea is to have this dispatching being done in a hash table. Since the table is dynamic the dispatching can be changed at run time (late binding).

Although I appreciate the "get my quickly from A to B" qualities of Python most of my daily business is based on good old C and Java. In this post I want to sketch out how function dispatching could be implemented in C - as usual as high level as possible.

Here is a naive Python example of using a dispatch table. See the last code example of this post of a more Pythonic version. This following code will be the template of our transformation to C later:

#!/usr/bin/python3

def _sumAll(numberList):
    sum = 0
    for number in numberList:
        sum = sum + number
    
    return sum

def _sumEven(numberList):
    sum = 0
    for number in numberList:
        if number % 2 == 0:
            sum = sum + number

    return sum

def _multiplyAll(numberList):
    prod = 1
    for number in numberList:
        prod = prod * number
    
    return prod


dispatchTable = {
    'sumAll' : _sumAll,
    'sumEven' : _sumEven,
    'multiplyAll' : _multiplyAll
}

def accumulateList(method, numberList):
    return dispatchTable[method](numberList)

numbers = (2,4,5,6)

print(accumulateList('sumAll', numbers))
print(accumulateList('sumEven', numbers))
print(accumulateList('multiplyAll', numbers))

Dispatching takes place in accumulateList where the dictionary dispatchTable is being looked up for the entry method. The function returned  is directly executed, hence the numberList argument.

So let'S look at C. As a friend of high-level expressions I'm using as usual GLib data structures. GList for the number list and GHashtable for the dispatch table.
#include <stdio.h>
#include <glib-2.0/glib.h>

static GHashTable* dispatchTable;

int _sumAll(GList* numberList) {
    int sum = 0;
    GList *iter = numberList;

    while(iter != NULL) {
        sum = sum + GPOINTER_TO_INT(iter->data);
        iter = g_list_next(iter);
    }

    return sum;
}

int _sumEven(GList* numberList) {
    int sum = 0;
    GList *iter = numberList;

    while(iter != NULL) {
        int number = GPOINTER_TO_INT(iter->data);
        if (number % 2 == 0) {
            sum = sum + number;
        }
        iter = g_list_next(iter);
    }

    return sum;
}

int _multiplyAll(GList* numberList) {
    int prod = 1;
    GList *iter = numberList;

    while(iter != NULL) {
        prod = prod * GPOINTER_TO_INT(iter->data);
        iter = g_list_next(iter);
    }

    return prod;
}

void createDispatchTable() {
    dispatchTable = g_hash_table_new(g_str_hash, g_str_equal);

    g_hash_table_insert(dispatchTable, g_strdup("sumAll"), 
                        _sumAll);
    g_hash_table_insert(dispatchTable, g_strdup("sumEven"), 
                        _sumEven);
    g_hash_table_insert(dispatchTable, g_strdup("multiplyAll"), 
                        _multiplyAll);
}

int accumulateList(const char* method, GList* numberList) {
    int (*func)(GList*);
    func = g_hash_table_lookup(dispatchTable, method);

    return func(numberList);
}

void destroyDispatchTable() {
    g_hash_table_destroy(dispatchTable);
}

int main() {
    GList* numbers = NULL;
    createDispatchTable();

    numbers = g_list_append(numbers, GINT_TO_POINTER (2));
    numbers = g_list_append(numbers, GINT_TO_POINTER (4));
    numbers = g_list_append(numbers, GINT_TO_POINTER (5));
    numbers = g_list_append(numbers, GINT_TO_POINTER (6));

    printf("%i\n",accumulateList("sumAll", numbers));
    printf("%i\n",accumulateList("sumEven", numbers));
    printf("%i\n",accumulateList("multiplyAll", numbers));

    destroyDispatchTable();
    g_list_free(numbers);

    return 0;
}

The code structure is close to the Python example before. A remark for the strange GINT_TO_POINTER and GPOINTER_TO_INT macros: This is the GLib way of storing and retrieving integers in their data structures. For more details refer to the GLib manual.

createDispatchTable uses a GLib GHashtable to store string to function pointer pairs.

accumulateList is retrieving the right function pointer by looking up the dispatch table. As the next step the function is executed and it's result is directly returned.

Usually I would append a common prefix to the public functions createDispatchTable(),
accumulateLis()  and destroyDispatchTable() to indicate that they belong to one module (see here for details) but for this example I tried to keep it simple.

So what do we think about that. Well, of course we could add some macro magic to shrink certain function calls (like the g_list_append) but I tend to use the C language straight, falling back on the preprocessor only if I can't achieve my goals directly.

The reason for that is more related to (good) code style. A macro always adds a new level of indirection which needs to be resolved by a human brain when trying to understand the code.  Eclipse CDTs macro expansion feature is definitly helpful here but I rather live without personal syntactic sugar.

The matter is different little fellows like GINT_TO_POINTER and GPOINTER_TO_INT. They represent a feature which can't be accomplished by using the language straight - so their fine.

I personally would like to see the definition of the dispatch table somehow outside a function, more prominent and if I could choose defined by something like designated initializers.

The GHashtable approach does not support that so we would need to replace it by something like a struct (e.g. DispatchTableEntry) and an array of these DispatchTableEntry struct.  The accumulateList function would then iterate over this array of structs looking for the right entry.

I tried that approach but it has a couple of downsides. One thing is that for simple usage of designated initializers the dispatch table array ideally has a fixed size. My personal favorite, a NULL terminated array of unknown length would lead to a rather odd syntax. So there is a trade-off here.

Also, implementing my own lookup functionality in accumulateList isn't what I was looking for - I wanted to use this out of the shelf.

An other obvious approach would be to define enums for the function names and use them as an index of an ordinary C array where the value would be the according function pointer. The lookup would be just a simple array index access using the enum as well.

Beside the missing runtime flexibility (you can't add enums at runtime) this approach has the problem that you maintain data at two sections: a new dispatch route would mean an entry in enums (new function name) and an extra entry in the array (the actual dispatch entry).

To my knowledge the best solution for this double data maintenance issue are X macros whose philosophy dates back to the 1960s. When you're in a pure C environment (poor you) this would be my way to go.

After weighting my options I stuck with the C implementation above. To add a new dispatch route function createDispatchTable has to be extended. Everything else is using battle proof implementations (GLib functions) in favour of (once again) rolling my own stuff.

To summarize the C example: this is as good as it gets in (high-level) C.

To conclude I promised to provide a Pythonic version of our example:
#!/usr/bin/python3

from operator import add,mul
from functools import reduce

onlyEvenFilter = lambda x: x % 2 == 0

dispatchTable = {
    'sumAll' : lambda list: reduce(add, list),
    'sumEven' : lambda list: reduce(add, filter(onlyEvenFilter, list)),
    'multiplyAll' : lambda list: reduce(mul, list)
}

def accumulateList(method, numberList):
    return dispatchTable[method](numberList)

numbers = (2,4,5,6)

print(accumulateList('sumAll', numbers))
print(accumulateList('sumEven', numbers))
print(accumulateList('multiplyAll', numbers))

That is more then 80 line of code in C versus 21 in Python - the same functionality, expressed more clearer (in my opinion) in 1/4 of the code ;-)

Sonntag, 27. April 2014

Python doctest

Most of my exercises for SCIP come as a stub function where you have to implement the logic. To provide a way to self test your implementation, the stub functions contain also something called doctests.

doctests are a nice way to quickly add tests to your functions. This is what the Python manual says: The doctest module searches for pieces of text that look like interactive Python sessions, and then executes those sessions to verify that they work exactly as shown.

Here is an example of one of my exercises:
from operator import add, sub
def a_plus_abs_b(a, b):
    """Return a+abs(b), but without calling abs.

    >>> a_plus_abs_b(2, 3)
    5
    >>> a_plus_abs_b(2, -3)
    5
    """
    if b < 0:
        op = sub
    else:
        op = add
    return op(a, b)
To run the two tests in the comment against the implementation I'm using the following command:
python3 -m doctest -v file.py