Thursday, October 22, 2009

Armstrong Thesis (Chapter 4)

This chapter takes us in deeper into Erlang programming language and the various techniques of abstracting out concurrency, error handling, and intentional programming.

Armstrong makes an interesting statement by having the expert programmers write the difficult modules and the less experienced programmers write the easy modules. This would be a prime opportunity for applying pair programming in order to take junior developers under your wing and guide them to greatness.

He does go on to discuss how the generic component should hide the details of concurrency and fault-tolerance from the plugins, and the plugins should be written using only sequential code with well-defined types. One of the main points is the plugin can contain errors and not crash the server along with allowing the plugin to be modified dynamically.

I am glad I do not depend on publishing Erlang code in order to put food on the table for myself and the family. The syntax is not terrible or complicated, but it is different from your regular iterative programming language. In the examples I have seen, there are no data types or declaring of variables required. Yes, you can do a lot of exciting things with little code but at what expense.

Armstrong identifies the Erlang philosophy for handling errors:
  • Let some other process do the error recovery.
  • If you can't do what you want to do, die.
  • Let it crash.
  • Do not program defensively.
From the Erlang perspective, exceptions occur when the run-time system does not know what to do and errors occur when the programmer doesn't know what to do. The worker process is introduced as the one doing the real work and the supervisor observes and handles the errors. The idea is to let the worker do what the worker does best and let someone else worry about the errors and how they should be handled. If you think about it, most of the code you write with try-catch blocks have all the functional code and error handling code contained in the same method. The Erlang philosophy is completely different than what you have likely experienced with C++ or Java.


Tuesday, October 20, 2009

Event-Based and Map Reduce Patterns

The event-based, implicit invocation, pattern implements a central event medium (i.e. manager) for handling the registration of and dispatching notification to listeners of events posted by the announcer. This concept seems logical so each announcer does not have duplicate similar code for handling registrations from listeners. By utilizing a central multi-threaded medium, many announcers of various events can take advantage of load balancing the notifications to the listeners.

It seems the event-based pattern use of the medium allows greater decoupling over the observer pattern. The announcer is not responsible for knowing which listeners are subscribed to the events as this is handled by the "third-party" medium. I think it actually simplifies the interface and modularizes the processes more. For greater number of listeners and guarantee of message delivery, systems may utilize middleware API like the Java Messaging Service (JMS) or commercialized products like JBoss or SonicMQ.

The map reduce pattern resembles the divide-and-conquer or fork/join framework. The idea is to split up the computations or various data retrieval tasks into smaller pieces and allow multiple threads or processor cores to independently obtain a result and then aggregate the results into a single response.

Errors in the map reduce pattern should be handled by the application developer as different errors require different actions. Depending on the data, an error may not be critical enough to cause the whole computation to be null and void.

Armstrong Thesis (Chapter 2)

The next couple of weeks will involve reading Joe Armstrong's thesis, Making reliable distributed systems in the presence of software errors, presented to the Royal Institute of Technology in Stockholm, Sweden in December 2003. The topics and issues described will be intriguing as we read each chapter.

This chapter describes an architecture for building fault-tolerant systems required for telecommunications switching networks. If you think about it, you expect your aging rotary dial phone to always get a dial tone when you pick up the receiver and be able to complete a phone call with no interrupts.

Telecommunications systems have some of the most stringent technical requirements. Due to the vast number of customers, switching systems are inherently concurrent and distributed across multiple locations of varying distances. These same systems are designed for many years of continuous operation requiring the performance of software or hardware updates without stopping the system.

The thesis advocates fault-isolation and forbids the use of shared data to deprecate the need for locks or mutexes. A software error in a concurrent process should not influence processing in the other processes in the system. The isolation is developed further by only allowing processes to communicate by message passing. This concept is intriguing as I have worked on systems implementing this type of isolation and how well it has worked when one process has an error. Unfortunately, if certain processes error out or crash, the rest of the system may not receive any message traffic to continue processing.

Armstrong suggests the use of the Erlang programming language to satisfy the requirements set forth in the thesis. Erlang was designed by Ericsson to support distributed, fault-tolerant, soft real-time, non-stop applications. The first version was actually developed by Joe Armstrong 17 years earlier.

I look forward to reading the remaining chapters to see what insight Armstrong can provide about telecommunications systems and the implementation of the architectural model.

Thursday, October 15, 2009

Pipes & Filter, Layered Systems, Iterative Refinement

We had previously read whitepapers on pipes & filters and layered systems. This time we also add an unfamiliar pattern called Iterative Refinement. The information presented in the whitepapers was much more intuitive and self-explanatory than the pattern information presented by the Parallel Computing Laboratory at Berkeley.

I really wish there was more information on each one of the patterns. Maybe I have been spoiled by the Gang of Four and Head First, but I receive so much more detail from these texts than what the online OPL has provided. Not to mention the numerous code examples in the texts compared the non-existent examples online. I am a visual type of person and appreciate when the examples are provided for my benefit. Since this is a website, the patterns could be under constant update or have plans to be expanded. The published papers (or scanned pages from a book) read previously satisfied my knack for examples.

As mentioned earlier, the Iterative Refinement was unfamiliar to me. Even after reading the pattern a couple of times, I am not confident as to what this pattern is used for. I realize I am not the only one with a quizzical look on my face after reading comments from other classmates. This almost sounds like it could be applied to the divide and conquer concept or an algorithm that requires multiple recursive calls in order to complete a calculation. I would like to request a more thorough explanation or example of the Iterative Refinement pattern.

Wednesday, October 14, 2009

CHESS

CHESS is an automated concurrency testing tool for finding and reproducing Heisenbugs in your concurrent programs.

You might ask yourself, "What is a Heisenbug?" It is a bug in a computer program that goes away or radically changes its behavior when attempts are made to investigate it. If you have ever programmed with threads, you have likely come across a Heisenbug. Do you remember that time when a thread was deadlocking or returning the wrong value and the error no longer occurred after adding a debug statement around the suspected area of code? The case of the error no longer occurring is the Heisenbug.

It is unfortunate CHESS is so limited as to which languages and platforms are supported. As a product developed by Microsoft Research, CHESS is only available for the Windows platform requiring Windows 2003 or later, 32-bit, x86, and Visual Studio 2008. Looks like I won't be able to use CHESS for quite some time until there is a Linux or Mac version available. With all of the useful features and possible exposure, I would expect an open-source team to devise a CHESS version that is compatible with other platforms. Even developing a version for Java or C++ would be a step in the right direction.

I am impressed by the number of iterations, permutations, and interleavings the tool can go through in such a short amount of time. There would have been many hours saved troubleshooting various issues in the past. The fact CHESS can learn and reproduce a failed execution over and over again. Repetition of the error is key to troubleshooting a problem. CHESS definitely corners the market on being able to capture and explore all interleaving determinism for large or small systems.

Tuesday, October 13, 2009

Rereading the Classics (Beautiful Architecture - Chapter 14)

We have finally blasted our way through the Beautiful Architecture book with the final chapter on Smalltalk and architecture. Like some of my classmates, I learned about and had hands-on experience with Smalltalk in Ralph Johnson's CS598RJ class at UIUC. I highly recommend the class to anyone wanting to experience a fully object-oriented language (and needing another 500-level credit).

As with any new language, using Smalltalk for the first time is a bit overwhelming. You have new syntax, new commands, and a new GUI (if using Squeak). "Modern-day" programming languages such as Java, Python, and Ruby have been influenced by concepts from Smalltalk. It is unfortunate Smalltalk is not more popular among developers. I would be interested in seeing a mainstream software application developed in Smalltalk. I am not aware of a significant software package written solely in Smalltalk.

I would like to give a kudos to @JLSjr for his latest blog entry. Well stated!

You always want to jump to the end of a book to see how it ends. Even though it is not a suspense novel, the last line of the book sums it up nicely:

Architecture is a chaotic adventure because beautiful architecture alone is not enough; not only beauty, but also usefulness, is the law for architecture and programming alike.

Refactoring for Reentrancy

Prior to reading this paper, I had no significant understanding of the term 'reentrant'. The idea is a program can be reentrant is distinct executions of that program on distinct inputs cannot affect each other. Many existing Java programs are not reentrant because they rely on mutable global state.

The developers implemented the refactoring for reentrancy in a tool called Reentrancer as an extension to the the Eclipse Java development tools (JDT). The refactoring for making programs reentrant are:
  1. Removal of non-reentrant accesses to library global state.
  2. Encapsulation of static fields in the application in getter/setter methods.
  3. Replacing static initializers with explicit lazy initialization.
  4. Replacing global state with thread-local state.
  5. Transforming the application to use a fresh thread for each execution.
Knowing 2 of the 3 authors of this paper are from IBM, I can understand why the Reentrancer plugin is only available for Eclipse. What about programmers or development teams who do not use Eclipse? There are many hooks in place for plugins developed for the Eclipse IDE, but many non-conformers are missing out on the potential benefits of using a refactoring mechanism like Reentrancer. I do hope there is a way to apply automatic refactorings to code without having to use Eclipse all the time.

Sunday, October 11, 2009

ReLooper: Refactoring for Loop Parallelism

I had no idea this paper co-authored by Dig, Radoi, Tarce, Minea, and Johnson had not been published yet. With all of the potential benefits from ReLooper, I expected to find a slew of information on the internet about it. Much to my demise, there was more blog entries from my classmates than more insight into this Eclipse plugin.

As I am a hands-on person and have to experience the benefits first-hand, I was really hoping to find the plugin available in the community. Again, my search returned no results. Even the Eclipse and Eclipse plugin website do not mention ReLooper. I have not had much exposure or opportunity to investigate parallel development. As with any automated tool, I am always a little hesitant to accept it for face value based on a technical paper.

Danny Dig is presenting/demonstrating ReLooper at OOPSLA 2009 on 28 October. It will be interesting to see how the plugin is received and what topics of discussion are spawned from the presentation. In addition to OOPSLA, there appears to be plans to formally present the paper at the 32nd International Conference on Software Engineering in Cape Town, South Africa in May 2010.

Saturday, October 10, 2009

Object-Oriented vs. Functional Programming (Beautiful Architecture - Chapter 13)

For those not familiar with the term, you might ask what is functional programming? Functional programming is a style of programming that emphasizes the evaluation of expressions rather than the execution of commands.

UIUC students (undergraduate and graduate) will learn about functional programming and OCaml if they take CS 421, Programming Languages & Compilers, as part of their degree. Students will be exposed to and receive hands-on experience as to how a functional programming language eases the pain of writing the various components of a common code compiler. It does take some time getting used to the syntax and break out of the shell of imperative programming.

Functional programming has its place, but that place is not in everyday software development. Maybe I am biased since the industry of my employment relies on modular, reliable, extensible, and maintainable software. That does not mean C++ or Java is the answer to all software development projects. Object-oriented concepts applied through common development languages allows the majority of software engineers to understand and maintain the code.

We all know the keys to good software architecture. Make sure code is extensible so modifications affect as few modules as possible. A one-module solution does not support reusability. Modularity is the key to successful software design.

I, personally, found it more difficult to troubleshoot or debug functional program code. It was uncomfortable to comprehend the logic and try to apply patterns or refactor your code. The same ideas or concepts that have been ingrained in our brains are not easily interchangeable between object-oriented and functional programming.

Wednesday, October 7, 2009

Refactoring Sequential Java Code for Concurreny via Concurrent Libraries

With all of the talk about locks, threads, forks, and atomicity, the lessons being taught this semester in CS423, Operating System Design, with Dr. Sam King provide a reasonable understanding of the concepts discussed in this paper.

Atomicity is key when dealing with parallelism. In case you are not aware of the concept, atomicity can be thought of as a transaction on a database -- it either happens in its entirety without interruption or does not happen at all. No events from other threads can happen in between the start and stop of an atomic event.

As I was reading the paper, the first question to come to mind was how does a call to ConcurrentHashMap's putIfAbsent perform an update without locking the entire map? It is ideal for no updates to occur on an object, especially a queue or map, when being read or updated. The theory later came to light when it was identified only the part of the map being read or updated would be locked. The concept is fairly intriguing as I am not aware of it ever being done before quite that way. It means other threads could ideally continue to operate on other parts of the hash without interfering with other operations.

Why are there no atomic APIs in AtomicInteger for multiplication and division operators? Unfortunately, this answer was never explained. I wonder if it is because you may not end up with an integer as the result.

I greatly appreciate the consideration of not changing the original interface of a recursive method when converting to ForkJoinTask. Interfaces should not change and any change to the logic should be hidden from external clients. This is very critical when other systems depending on your system for a service expect that interface to always be there. Depending on the type system being impacted, a change to the interface could be very costly.

Concurrencer is more efficient and more accurate than refactoring by hand. Concurrencer produces the correct code in about 10 seconds and identified more opportunities for using the new, scalable APIs. Manual conversion is always error-prone. Having used refactoring tools in Eclipse, I am always hesitant about fully automating some manual actions. It would be wise to backup the current code into CVS or subversion before applying any automatic changes. After the changes are complete, you can do a diff to visually verify the changes are accurate. There will likely always that odd case where the automated tool did not know how to handle your code properly.

Tuesday, October 6, 2009

Building Cathedrals (Beautiful Architecture - Chapter 12)

Having a particular interest in the many successes of Linux and KDE, this was a great chapter for highlighting some of the growing pains experienced on Open-Source projects.

Whether it be Free Software or commercially-developed, all software face technical challenges. Data is always growing and is becoming more complex. Users want easier-to-use interfaces; responsive and not overly complex interactions with software and high reliability, stability, and safety. Developers expect well-maintained APIs, clean migration paths, and functionality at the level of their day jobs.

With the Free Software development teams being so disparate and spread across the world, it is a wonder how anything was agreed upon. Communication is still key. It was recognized where most decisions made in 15-minute stand-up meetings , it may take days for each person in other hemispheres to provide their feedback or opinions.

One of the interesting aspects of the KDE community is the lack of commercial governance. Developers did not want to be influenced or pressured by executives providing funding in order to take control of the project. There are no dictators cracking whips and shouting orders to the minions in the dungeon.

It was a pleasure to read a chapter where the author does not delve too deep into the architecture and confuse the reader. The sections on the Akonadi framework and KDEPIM were very enlightening as to the various approaches considered in the software integration and architecture. A decision is never going to be perfect or the "one size fits all" choice for everyone involved. It is a guarantee applications are going to be decommissioned when something better comes along, libraries will be replaced, and interfaces will change. Software and system development is not stale. Climb aboard and be part of the innovation.