What I like most about Armstrong's approach to a fault-tolerant system is the clear separation between code that computes a task (worker processes) and code that handles error, exceptions, and/or failures. When these 2 things are combined, it makes the code more complex and more opportunity for bugs. I see this at my job all the time. Try/catch statements within try/catch statements within loops within conditional blocks etc ……. leads to very ugly code!
I'm a firm believer that simplicity is key to writing fault-tolerant systems. For this reason, I think the supervision hierarchies explained in this chapter is a good and intuitive strategy for having the system operate when there's an error in the system.
Also, Armstrong does a nice job explaining the differences between an error, exception, and a failure.
Error: "we will define an error as a deviation between the observed behavior of a system and the desired behavior of a system."
Exception: "Exceptions are generated automatically by the run-time system when the run-time system cannot decide what to do."
Failure: "If there is no 'catch handler' for an exception then the process itself will fail."
Monday, November 2, 2009
Thursday, October 22, 2009
Armstrong Thesis - Chap. 4
The author states that it is impossible to write concurrent code in a side effect free manner. Do you agree?
The author didn't exactly say it's "impossible" but he did say that it's not possible. I believe you can create side-effect free concurrent code, it's just much more difficult to verify that it's side-effect free.
Erlang provides primitives for performing concurrent action (modules/ports). What are the advantages/disadvantages of using this vs. libraries or OS capabilities? Have you found any particularly useful libraries?
Well, in an interview with Joe Armstrong http://www.ddj.com/linux-open-source/201001928?cid=RSSfeed_DDJ_OpenSource he says that Erlang processes are lighter weight than threads so this is an advantage over OS capabilities. I could see how having these primitives can help establish consistency in their usage and avoid multiple people from developing their own version of concurrent libraries. If you don't like what the language provides, you can always create a library that extends the built-in primitives.
Is it possible to totally abstract out concurrency? The author lists several advantages, are there any disadvantages?
There are different levels of abstraction. I think the examples Armstrong gave did a good job illustrating the separation of functional, sequential code from the non-function, concurrent code. If having the concurrency implementation in a different module & file from the functional implementation is sufficient to say "total abstraction", then Erlang clearly makes this possible. Loosely coupled systems almost always have the upper-hand so if there are any disadvantages, I would just say that it may make it a bit more difficult for new programmers to understand.
Fault tolerance is demonstrated via catching crashes and timing out replies. The author also mentions using supervisors to handle this case. Do you have any experience with either of these patterns for fault tolerance?
No unfortunately I've haven't had any experience with developing a supervisor that deals with the errors/crashes of worker processes/threads.
The author lists several of the abstractions held entirely in the server module and aided by Erlang. Are any of these abstractions ONLY possible in Erlang?
Hot code loading that can be used for dynamic upgrades comes to mind as shown in the "swap_code" function of Figure 4.7.
Would there be any difficulties of following the error handling recommendations (let another process fix it, supervisors, let it crash) in another language than Erlang?
You would have to create & run an additional server process to do the error handling. For e.g., you would have to create and compile ErrorHandlingServer.java or ErrorHandling.cpp into different jars/executables and then run them. More coding would be required for communication than Erlang.
How important is it to use intentional programming when it comes to maintenance? (The author gave the example of history of the Dictionary API)
Very important but at the same time, it's difficult to assess whether certain names imply different implementation. In many cases, only time will tell whether you need to break up a method into several methods with more specific names as was the case with the lookup --> fetch, search, is_key example.
The author didn't exactly say it's "impossible" but he did say that it's not possible. I believe you can create side-effect free concurrent code, it's just much more difficult to verify that it's side-effect free.
Erlang provides primitives for performing concurrent action (modules/ports). What are the advantages/disadvantages of using this vs. libraries or OS capabilities? Have you found any particularly useful libraries?
Well, in an interview with Joe Armstrong http://www.ddj.com/linux-open-source/201001928?cid=RSSfeed_DDJ_OpenSource he says that Erlang processes are lighter weight than threads so this is an advantage over OS capabilities. I could see how having these primitives can help establish consistency in their usage and avoid multiple people from developing their own version of concurrent libraries. If you don't like what the language provides, you can always create a library that extends the built-in primitives.
Is it possible to totally abstract out concurrency? The author lists several advantages, are there any disadvantages?
There are different levels of abstraction. I think the examples Armstrong gave did a good job illustrating the separation of functional, sequential code from the non-function, concurrent code. If having the concurrency implementation in a different module & file from the functional implementation is sufficient to say "total abstraction", then Erlang clearly makes this possible. Loosely coupled systems almost always have the upper-hand so if there are any disadvantages, I would just say that it may make it a bit more difficult for new programmers to understand.
Fault tolerance is demonstrated via catching crashes and timing out replies. The author also mentions using supervisors to handle this case. Do you have any experience with either of these patterns for fault tolerance?
No unfortunately I've haven't had any experience with developing a supervisor that deals with the errors/crashes of worker processes/threads.
The author lists several of the abstractions held entirely in the server module and aided by Erlang. Are any of these abstractions ONLY possible in Erlang?
Hot code loading that can be used for dynamic upgrades comes to mind as shown in the "swap_code" function of Figure 4.7.
Would there be any difficulties of following the error handling recommendations (let another process fix it, supervisors, let it crash) in another language than Erlang?
You would have to create & run an additional server process to do the error handling. For e.g., you would have to create and compile ErrorHandlingServer.java or ErrorHandling.cpp into different jars/executables and then run them. More coding would be required for communication than Erlang.
How important is it to use intentional programming when it comes to maintenance? (The author gave the example of history of the Dictionary API)
Very important but at the same time, it's difficult to assess whether certain names imply different implementation. In many cases, only time will tell whether you need to break up a method into several methods with more specific names as was the case with the lookup --> fetch, search, is_key example.
Wednesday, October 21, 2009
Dense Linear Algebra, Graph Algorithms, Monte Carlo
The Dense Linear Algebra computational pattern reminds me of a compiler optimization to reduce the memory access miss rate taught in computer architecture courses. They teach the same strategy of organizing the computation in a blocked manner as show in figure 4. Their argument is that it will improve spatial and temporal locality, which will reduce the number of cache misses. What the article brings to the table is that you can auto-tune the size of the block to obtain the right balance and you can use SIMD instructions to execute the same operation on multiple variables.
The Graph Algorithms pattern takes me back to the Algorithms course I took last year. For sure, one can't understand this if they haven't taken the Algorithms course. What's new to me is the partitioning operations. In other words, I haven't heard of Kernighan-Lin, Fiduccia-Matheyses, nor ParMetis algorithms. I can see how partitioning the graph structures can allow multiple, independent threads process them in parallel. If each thread can produce a subresult, I can also see how this could be used in dynamic programming algorithms.
The Monte Carlo pattern was difficult to understand at first but the Estimating Pi example along with some help from my wife (who's an actuary) made this more clear. Apparently the Monte Carlo method is used extensively by quantitative analysts to simulate the Black-Scholes model for predicting prices of derivatives.
The Graph Algorithms pattern takes me back to the Algorithms course I took last year. For sure, one can't understand this if they haven't taken the Algorithms course. What's new to me is the partitioning operations. In other words, I haven't heard of Kernighan-Lin, Fiduccia-Matheyses, nor ParMetis algorithms. I can see how partitioning the graph structures can allow multiple, independent threads process them in parallel. If each thread can produce a subresult, I can also see how this could be used in dynamic programming algorithms.
The Monte Carlo pattern was difficult to understand at first but the Estimating Pi example along with some help from my wife (who's an actuary) made this more clear. Apparently the Monte Carlo method is used extensively by quantitative analysts to simulate the Black-Scholes model for predicting prices of derivatives.
Sunday, October 18, 2009
Armstrong thesis - Chap. 2
Chapter 2 of Armstrong's thesis is describing how to build fault-tolerant systems with very demanding requirements. The solution is to implement modules as isolated processes with no sharing of resources, message passing communication to achieve concurrency and error detection, and a fail-fast policy when a process crashes; similar to how processes in operating systems work. But it seems that in order to achieve all of this, you need the right hardware, the right OS, and a programming language that allows developers to implement fault-tolerant systems that support all of these requirements. They're asking for a lot from a system so I'm curious to understand the details to their approach. They made several references to Tandem computers so I wonder if their approach is similar to providing redundancy at every level.
The chapters mentions that programming languages can't be used for building robust systems because they're not able to "isolate software components from each other". Well, couldn't I just simply create new processes in C++ or Java to create this isolation? Or maybe a language such as Erlang provides the ability to develop an application where the underlying system in which it runs will separate different modules into processes (haven't read Chap. 3 of the thesis yet). If this is case, then it's true C++ nor Java have frameworks that separate their modules into separate processes. At least none that I know about.
I didn't understand how adding more processes could not affect the original system. I mean, everyone knows that adding more processes can consume a lot of CPU and memory resources. Unless they mean that sufficient hardware should exist for supporting 100,000 processes! Also, how are object-oriented languages not true asynchronous messages. Many of them provide the ability to specify a call-back so that programs don't block on an RPC call. What does a COPL have that an OO language doesn't with respect to this?
Erlang's support for hot code loading is one I've never heard about but I can see its enormous potential if you can combine it with an AOM system. Not only would you be able to keep your system running during upgrades but this could realize an extremely flexible system.
The chapters mentions that programming languages can't be used for building robust systems because they're not able to "isolate software components from each other". Well, couldn't I just simply create new processes in C++ or Java to create this isolation? Or maybe a language such as Erlang provides the ability to develop an application where the underlying system in which it runs will separate different modules into processes (haven't read Chap. 3 of the thesis yet). If this is case, then it's true C++ nor Java have frameworks that separate their modules into separate processes. At least none that I know about.
I didn't understand how adding more processes could not affect the original system. I mean, everyone knows that adding more processes can consume a lot of CPU and memory resources. Unless they mean that sufficient hardware should exist for supporting 100,000 processes! Also, how are object-oriented languages not true asynchronous messages. Many of them provide the ability to specify a call-back so that programs don't block on an RPC call. What does a COPL have that an OO language doesn't with respect to this?
Erlang's support for hot code loading is one I've never heard about but I can see its enormous potential if you can combine it with an AOM system. Not only would you be able to keep your system running during upgrades but this could realize an extremely flexible system.
Saturday, October 17, 2009
Event Based
I think the article could have given a formal definition of Implicit Invocation within the context of Event-based systems. Here is one I found from "An Introduction to Software Architecture" by David Garlan and Mary Shaw of Carnegie Mellon University:
"The idea behind implicit invocation is that instead of invoking a procedure directly, a component can announce (or broadcast) one or more events. Other components in the system can register an interest in an event by associating a procedure with the event. When the event is announced the system itself invokes all of the procedures that have been registered for the event. Thus an event 'implicitly' causes the invocation of procedures in other modules."
This paper http://www.mach-ii.com/resources/intro_to_implicit_invocation.pdf does a better job explaining the Event-based pattern although it doesn't explain how it could be used for parallelism. Also it says that Event-based is an Architectural Style, implying that it's not a pattern. It says that design pattern such as MVC implement architectural styles. So how do we draw the line between what's a pattern and what's an architectural style? I always thought architectural styles was a subset of patterns.
"The idea behind implicit invocation is that instead of invoking a procedure directly, a component can announce (or broadcast) one or more events. Other components in the system can register an interest in an event by associating a procedure with the event. When the event is announced the system itself invokes all of the procedures that have been registered for the event. Thus an event 'implicitly' causes the invocation of procedures in other modules."
This paper http://www.mach-ii.com/resources/intro_to_implicit_invocation.pdf does a better job explaining the Event-based pattern although it doesn't explain how it could be used for parallelism. Also it says that Event-based is an Architectural Style, implying that it's not a pattern. It says that design pattern such as MVC implement architectural styles. So how do we draw the line between what's a pattern and what's an architectural style? I always thought architectural styles was a subset of patterns.
Friday, October 16, 2009
Pipes & Filters, Layered Systems, Iterative Refinement
So far the pattern descriptions from the Berkeley wiki seem to provide a reasonably good summary. By no means is it comprehensive but if one is familiar with the Pipe-n-Filter & Layered patterns, then it's straight forward. The Iterative Refinement pattern, though, was a hard read. By rereading this article twice, one can get a high-level understanding. VHDL was the first thing that came to mind for applying iterative refinement but I was a bit disappointment that not enough known use examples were given.
It seems to me that it would be easier to implement reentrant applications in Pipe-n-Filter and Layered architectures as opposed to some others, simply because they promote more local state dependencies and less shared state dependencies between the filters/layers (because they promote the modular ability to interchange filters/layers with ease). And this reentrancy would allow additional parallelism on top of the parallelism that could be achieved through pipelining. As the article states, pipeline parallelism can be achieved along a linear branch while task parallelism can be done for tasks along parallel branch.
On a side note, the description of how a filter cannot invoke/control another filter up-stream or down-stream is a great example of showing how it's data abstraction but not necessarily object-oriented programming. Most students, including myself, have a hard time thinking about data abstraction without thinking about objects encapsulating data.
Finally, the Layered systems article says "Increasing abstraction increases code readability and project organization" and I'm not sure I agree with this. Usually when you increase abstraction, it makes it harder for one to read the code because you're constantly going through all these redirections in order to search for functions that do actual work. Smalltalk and the Adaptive Object Model are examples that come to mind. Although one can argue that Smalltalk makes up for all these redirections by promoting methods with a few lines of readable code.
It seems to me that it would be easier to implement reentrant applications in Pipe-n-Filter and Layered architectures as opposed to some others, simply because they promote more local state dependencies and less shared state dependencies between the filters/layers (because they promote the modular ability to interchange filters/layers with ease). And this reentrancy would allow additional parallelism on top of the parallelism that could be achieved through pipelining. As the article states, pipeline parallelism can be achieved along a linear branch while task parallelism can be done for tasks along parallel branch.
On a side note, the description of how a filter cannot invoke/control another filter up-stream or down-stream is a great example of showing how it's data abstraction but not necessarily object-oriented programming. Most students, including myself, have a hard time thinking about data abstraction without thinking about objects encapsulating data.
Finally, the Layered systems article says "Increasing abstraction increases code readability and project organization" and I'm not sure I agree with this. Usually when you increase abstraction, it makes it harder for one to read the code because you're constantly going through all these redirections in order to search for functions that do actual work. Smalltalk and the Adaptive Object Model are examples that come to mind. Although one can argue that Smalltalk makes up for all these redirections by promoting methods with a few lines of readable code.
Wednesday, October 14, 2009
CHESS
A deterministic solution for finding Heisenbugs? Is this too good to be true? Looking around in the Internet for 15 minutes and I could not find another debugging solution that claims to provide exhaustive test coverage of all possible interleavings of a multi-threaded program and still be able to reproduce a discovered Heisenbug. Given that it was produced my Microsoft researchers, it only works for the Win32, .NET, and Singularity frameworks because CHESS relies on understanding the semantics of the program in order to produce preemption points for possible interleavings. So a Java implementation of CHESS would need to understand Java's semantic so that it can put preemption points whenever it make calls to the thread libraries or makes system calls. Though they wouldn't release the source code for CHESS, I don't see why someone can't reproduce this in Java using the same ideas. Would it be considered "stealing" the ideas from Microsoft? I wonder if Microsoft will market this to lure more developers to use .NET.
At first, I was skeptical about how they could possibly cover all scenarios but they relied on several heuristics to minimize the # of possible interleavings. They limited the areas where preemption can occur to synchronization points and at instructions that participate in data races.
At first, I was skeptical about how they could possibly cover all scenarios but they relied on several heuristics to minimize the # of possible interleavings. They limited the areas where preemption can occur to synchronization points and at instructions that participate in data races.
Tuesday, October 13, 2009
Refactoring for Reentrancy
I'm glad this article used test cases as examples where reentrancy can be used because earlier this year, I ran into issues running JUnit tests on a multi-threaded application that depended on each execution to be independent from the other. I had to manually re-initialize persistent data after each run. Now I at least know one can wrap static variables with ThreadLocal and use TestRunner to spawn threads that utilize their own copy :-). Aside from testing, other applications for reentrancy are in interrupt handlers where interrupts can be dispatched to multiple cores.
Given that I have limited experience with using reentrancy for creating multithreading applications, it appears to me that the solution does provide a solution that makes a program reentrant. Ideally, all variables would be local so as to avoid the whole transformation of static variables but it's understandable that this is used for legacy code. However, the transformation makes the code look really ugly in this simple example so I'm having a hard time figuring out how this would scale in an enterprise application.
On a side note, I don't think object fields need to be made thread-local if a new instance is created for each execution. Also, I don't think shared resources such as standard output or a printer can be thread-local. In the paper, they circumvented this by outputting to a logger as opposed to standard output. In cases where it's necessary to output to a printer or standard output, one may have to introduce a mechanism for serializing the output in a predictive order. And finally, reentrancy does imply thread-safety because multiple threads can execute the same code without interfering with each other. But thread-safety does NOT imply reentrancy because thread-safety cannot guarantee a method would return the same output for a given input each time its executed.
Given that I have limited experience with using reentrancy for creating multithreading applications, it appears to me that the solution does provide a solution that makes a program reentrant. Ideally, all variables would be local so as to avoid the whole transformation of static variables but it's understandable that this is used for legacy code. However, the transformation makes the code look really ugly in this simple example so I'm having a hard time figuring out how this would scale in an enterprise application.
On a side note, I don't think object fields need to be made thread-local if a new instance is created for each execution. Also, I don't think shared resources such as standard output or a printer can be thread-local. In the paper, they circumvented this by outputting to a logger as opposed to standard output. In cases where it's necessary to output to a printer or standard output, one may have to introduce a mechanism for serializing the output in a predictive order. And finally, reentrancy does imply thread-safety because multiple threads can execute the same code without interfering with each other. But thread-safety does NOT imply reentrancy because thread-safety cannot guarantee a method would return the same output for a given input each time its executed.
Saturday, October 10, 2009
BA Chap. 14 - Rereading the Classics
One of the reasons I decided to pursue my career into Software Engineering is that developing software gives one the opportunity to create something of practical use in a relatively short time, even if it's programming something as simple as a time clock. But I admit that I've fallen in the trap of spending too much time trying to make UML diagrams as beautiful as possible, and resulted in delivering incomplete code. This article is sort of a wake up call to those who are more concern about decorations and ornaments as opposed to features that are more pragmatic.
Having said that, I found the article's comparison of languages such as Smalltalk, C++, Java, & Python to be very informative because it gives a better explanation of the advantages & disadvantages of each of these languages from an object-oriented perspective. For example, every newly defined class in Smalltalk is inherited from another class, which is in clear violation of the "Favor Composition Over Inheritance" principle. Interfaces in C++ is limited to defining abstract classes whereas in Java, one can explicitly define interfaces. Despite Smalltalk's limitations, though, having a purely object-oriented language "allows us to limit the number of syntactic constructs in the language". Lisp is another example of a purely object-oriented language where program and data are "lists".
I do remember half-a-decade ago that I was annoyed by the fact that Java did not support templates. Then they came out with Generics in SE 5.0 but this didn't calm my frustration because I still had to define a type through an interface as the article pointed out. Because of this, one could argue that Java is slightly limited in its support for polymorphism.
The biggest take away was that the argument of "statically typed languages being more protective of coding errors" is weak because the most difficult errors are actually run-time bugs. Syntax errors are straight-forward to figure out, especially with the use of IDEs such as Eclipse and Visual Studio. Appropriate run-time error messages for syntax errors and a call-stack should be sufficient for most debugging purposes.
Having said that, I found the article's comparison of languages such as Smalltalk, C++, Java, & Python to be very informative because it gives a better explanation of the advantages & disadvantages of each of these languages from an object-oriented perspective. For example, every newly defined class in Smalltalk is inherited from another class, which is in clear violation of the "Favor Composition Over Inheritance" principle. Interfaces in C++ is limited to defining abstract classes whereas in Java, one can explicitly define interfaces. Despite Smalltalk's limitations, though, having a purely object-oriented language "allows us to limit the number of syntactic constructs in the language". Lisp is another example of a purely object-oriented language where program and data are "lists".
I do remember half-a-decade ago that I was annoyed by the fact that Java did not support templates. Then they came out with Generics in SE 5.0 but this didn't calm my frustration because I still had to define a type through an interface as the article pointed out. Because of this, one could argue that Java is slightly limited in its support for polymorphism.
The biggest take away was that the argument of "statically typed languages being more protective of coding errors" is weak because the most difficult errors are actually run-time bugs. Syntax errors are straight-forward to figure out, especially with the use of IDEs such as Eclipse and Visual Studio. Appropriate run-time error messages for syntax errors and a call-stack should be sufficient for most debugging purposes.
Tuesday, October 6, 2009
Refactoring Sequential Java Code for Concurrency via Concurrent Libraries
Q1. Sometimes it is possible to retrofit parallelism by refactoring an existing sequential application. Other times the whole system needs to be re-architected for parallelism. What are the advantages/disadvantages of these approaches? When would you do one over the other?
The advantage of retrofitting parallelism in an existing sequential application is that the amount of work can be very minimal relative to re-architecting the whole application. On the flip-side, re-architecting the whole application can give the opportunity to provide a solid foundation for supporting parallelism, therefore, reducing the amount of work and errors associated with retrofitting parallelism. I would apply retrofitting when the time-to-market of an application is crucial and when only a small component of the application needs parallelism. However, if several components of the application are starting to smell do to the ugly code produced by retrofitting, then the team should consider re-architecting the application. Especially in the case when the team has some time to invest, re-architecting the application can save time in the long run.
Q2. There are many libraries that target concurrency and parallelism (e.g., Java's ForkJoinTask, Microsoft's TPL, Intel's TBB, OpenMP, MPI, etc.). What are the advantages and disadvantages of using parallel libraries?
In the case of the ForkJoin Task, it's included in Java 7 so no need to install/download additional packages. Also, due to the programming ease of Java, it seems straight-forward using Java's concurrency library from semantics point-of-view.
Q3: The approach presented in the paper puts the programmer in the driving seat: the programmer selects a snapshot of code, and a refactoring. The process is semi-automated, but not fully automatic.
Compare and contrast the refactoring approach with a fully automatic approach, like the one used in automatic parallelizing compilers.
The semi-automated approach forces the programmer to think more about what parts of the code should be parallelized and which parts should not. Along the same lines, it can provide more granularity, will simplify the implementation of an automated system, and will prevent an automated system from bloating the refactored code with unnecessary code, in which case the programmer would have to go back and remove the excess.
Q4: Some of the transformations presented in the paper make the code harder to understand (e.g., Converting recursion to ForkJoinTask).
What are some approaches to unclutter the parallel code?
In the ForkJoinTask conversion, I would create methods getLeftTask & getRightTask that return a Left task & Right task, respectively, of type SortImpl. This would be used to replace lines 30-36 of Figure 5 with:
SortImpl task1 = getLeftTask();
SortImpl task2 = getRightTask();
Q5: The paper presents three automated refactorings to make a program more parallel. By no means is this a comprehensive list of refactorings. What are some other refactorings that you have applied, or have seen in other projects?
At my work, I developed an application for deploying software to multiple computers from a server. Initially, it was a sequential deployment but because remote transfer & installation has unpredictable delay time for each remote machine, I had to refactor the code deploy the software in parallel. Basically, I just ran a loop that spawn a thread to deploy the software and blocked until they all came back.
Q6: The paper presents some empirical evaluation to support the claim that these automated refactorings are useful. What are some other factors that you would have liked to see evaluated?
I would've liked to have seen this strategy being applied to 3D games.
The advantage of retrofitting parallelism in an existing sequential application is that the amount of work can be very minimal relative to re-architecting the whole application. On the flip-side, re-architecting the whole application can give the opportunity to provide a solid foundation for supporting parallelism, therefore, reducing the amount of work and errors associated with retrofitting parallelism. I would apply retrofitting when the time-to-market of an application is crucial and when only a small component of the application needs parallelism. However, if several components of the application are starting to smell do to the ugly code produced by retrofitting, then the team should consider re-architecting the application. Especially in the case when the team has some time to invest, re-architecting the application can save time in the long run.
Q2. There are many libraries that target concurrency and parallelism (e.g., Java's ForkJoinTask, Microsoft's TPL, Intel's TBB, OpenMP, MPI, etc.). What are the advantages and disadvantages of using parallel libraries?
In the case of the ForkJoin Task, it's included in Java 7 so no need to install/download additional packages. Also, due to the programming ease of Java, it seems straight-forward using Java's concurrency library from semantics point-of-view.
Q3: The approach presented in the paper puts the programmer in the driving seat: the programmer selects a snapshot of code, and a refactoring. The process is semi-automated, but not fully automatic.
Compare and contrast the refactoring approach with a fully automatic approach, like the one used in automatic parallelizing compilers.
The semi-automated approach forces the programmer to think more about what parts of the code should be parallelized and which parts should not. Along the same lines, it can provide more granularity, will simplify the implementation of an automated system, and will prevent an automated system from bloating the refactored code with unnecessary code, in which case the programmer would have to go back and remove the excess.
Q4: Some of the transformations presented in the paper make the code harder to understand (e.g., Converting recursion to ForkJoinTask).
What are some approaches to unclutter the parallel code?
In the ForkJoinTask conversion, I would create methods getLeftTask & getRightTask that return a Left task & Right task, respectively, of type SortImpl. This would be used to replace lines 30-36 of Figure 5 with:
SortImpl task1 = getLeftTask();
SortImpl task2 = getRightTask();
Q5: The paper presents three automated refactorings to make a program more parallel. By no means is this a comprehensive list of refactorings. What are some other refactorings that you have applied, or have seen in other projects?
At my work, I developed an application for deploying software to multiple computers from a server. Initially, it was a sequential deployment but because remote transfer & installation has unpredictable delay time for each remote machine, I had to refactor the code deploy the software in parallel. Basically, I just ran a loop that spawn a thread to deploy the software and blocked until they all came back.
Q6: The paper presents some empirical evaluation to support the claim that these automated refactorings are useful. What are some other factors that you would have liked to see evaluated?
I would've liked to have seen this strategy being applied to 3D games.
Monday, October 5, 2009
BA Chap. 12 - When the bazaar sets out to build cathedrals
Since I've never worked with a community on an open-source project, I always wondered how developers from around the world are able to effectively work together to develop great software without a direct manager to report to, and without compensation. Sure there are some professionals that get paid by their employers for contributing code to these open-source communities. But even at my current job where my company invests vast amounts of resources do I have trouble getting things done when I work with foreign teams. The article said it best with, "Discussions that can be finished in 15 minutes in a stand-up office meeting may take days of arguing". It seems that they get their best work done when they meet in their quarterly/bi-annual/annual meetings and have these week-long coding sprints. But even then, what do they do when a contributor doesn't provide what he/she commits to do or when he/she quits? I find it astonishing that work actually gets done due to personal motivation, and that their pride alone can provide better quality code because developers are not rushed to meet a deadline.
Overall, the article's chronological description of their communities thought process throughout the evolution of Akonadi & ThreadWeaver was intellectually stimulating. I initially did not understand why they didn't Unit Test the PIM infrastructure. Automatically testing the core functionality to see if anything broke by a change in PIM could have saved them time. Then again if the code-base was very large, the effort to do unit-testing may not have been worth it. I originally thought that applying the adapter or façade pattern to abstract the support of multiple backend implementations would've solved the assumptions that made about limited data and application usage. But then I realized that it wouldn't have solved their concurrent access to data requirement. Also, I didn't understand why they didn't use a DB indexes for their data when they discussed their need to load the whole address book into memory. Then, they later explained that their data had to support multiple types so it had to be stored in the DB as string. Indexes doesn't help in this situation so Akonadi was implemented to support serializer plug-ins for components.
Threadweaver, similarly, had some clever architectural features in their job queue for concurrency. The queue made sure jobs were executed in sequence through the notion of Dependencies without the nasty use of a mutex!
Overall, the article's chronological description of their communities thought process throughout the evolution of Akonadi & ThreadWeaver was intellectually stimulating. I initially did not understand why they didn't Unit Test the PIM infrastructure. Automatically testing the core functionality to see if anything broke by a change in PIM could have saved them time. Then again if the code-base was very large, the effort to do unit-testing may not have been worth it. I originally thought that applying the adapter or façade pattern to abstract the support of multiple backend implementations would've solved the assumptions that made about limited data and application usage. But then I realized that it wouldn't have solved their concurrent access to data requirement. Also, I didn't understand why they didn't use a DB indexes for their data when they discussed their need to load the whole address book into memory. Then, they later explained that their data had to support multiple types so it had to be stored in the DB as string. Indexes doesn't help in this situation so Akonadi was implemented to support serializer plug-ins for components.
Threadweaver, similarly, had some clever architectural features in their job queue for concurrency. The queue made sure jobs were executed in sequence through the notion of Dependencies without the nasty use of a mutex!
Saturday, October 3, 2009
Fork/Join Parallelism
The first question that comes to mind is why do we need a framework for parallel computing? Doesn't the operating system in conjunction with hardware already provide this support for us? In the case of Java Fork/Join, doesn't the JVM provide some parallelization oomph ? Well, the article explicitly states that this framework is intended for programs that execute subtasks in parallel and, therefore, can not rely on the shortcomings of pthreads and the java.lang.Thread class from the perspective of task parallelism computing. It's worth restating their deficiencies as follows:
1. Thread synchronization and management is generalized to accommodate the different types of parallel computing so it unnecessarily blocks threads in task parallel programs.
2. Tasks are too coarse-granular that it "limits opportunities for exploiting parallelism".
But aren't there automated tools with configurable parameters that one can use for parallelization? This investigation led me to following results from Wikipedia:
"Automatic parallelization by compilers or tools is very difficult due to the following reasons:
* dependence analysis is hard for code using indirect addressing, pointers, recursion, and indirect function calls;
* loops have an unknown number of iterations;
* accesses to global resources are difficult to coordinate in terms of memory allocation, I/O, and shared variables.
"
For these reasons, we have the POSIX Thread library, Cilk, OpenCL, and CUDA among other programming models. And why Java? It provides more portability to fork/join programs since they can run on any machine that has a JVM. And one will not have to worry about porting the fork/join framework since it'll be included in Java SE 7 as listed in http://www.javaworld.com/community/node/3458. According to http://www.javaworld.com/javaworld/jw-12-2008/jw-12-year-in-review-2.html?page=4, there is a ParalleArray class that represents an array where you can perform operations such as filter, map, and apply on the array's data items in parallel. The ForkJoinPool class will provide the threads to perform these concurrent operations and "can automatically take advantage of increasing processor-core counts in the future without modifying the functions". This will be particularly useful for 16-32 core machines since SE 6 only functioned well for 4-8 core machines.
1. Thread synchronization and management is generalized to accommodate the different types of parallel computing so it unnecessarily blocks threads in task parallel programs.
2. Tasks are too coarse-granular that it "limits opportunities for exploiting parallelism".
But aren't there automated tools with configurable parameters that one can use for parallelization? This investigation led me to following results from Wikipedia:
"Automatic parallelization by compilers or tools is very difficult due to the following reasons:
* dependence analysis is hard for code using indirect addressing, pointers, recursion, and indirect function calls;
* loops have an unknown number of iterations;
* accesses to global resources are difficult to coordinate in terms of memory allocation, I/O, and shared variables.
"
For these reasons, we have the POSIX Thread library, Cilk, OpenCL, and CUDA among other programming models. And why Java? It provides more portability to fork/join programs since they can run on any machine that has a JVM. And one will not have to worry about porting the fork/join framework since it'll be included in Java SE 7 as listed in http://www.javaworld.com/community/node/3458. According to http://www.javaworld.com/javaworld/jw-12-2008/jw-12-year-in-review-2.html?page=4, there is a ParalleArray class that represents an array where you can perform operations such as filter, map, and apply on the array's data items in parallel. The ForkJoinPool class will provide the threads to perform these concurrent operations and "can automatically take advantage of increasing processor-core counts in the future without modifying the functions". This will be particularly useful for 16-32 core machines since SE 6 only functioned well for 4-8 core machines.
BA Chap. 11 - GNU Emacs
When I first began exploring the various applications that came with Fedora Core 3 in 2004, I originally thought Emacs was an over-bloated text editing application, with meaningless features. But reading this article made me realized how much I missed out!
One of the coolest features is its ability to pipeline commands for text to be navigated, searched, organized, trimmed, and sorted all at once. As the article explained, this is possible due to their Model Design of text buffers. Also, it provides support for text terminals while simultaneously managing graphical frames. These are features you can't do with Visual Studio nor Eclipse.
Using the MVC pattern is a natural choice for text editing applications. It proved to be particularly useful in the case of Emacs since their Controller code, in isolation from the Model & View, was almost done entirely in Emacs Lisp. I haven't written code in any language related to Lisp but, apparently, Emacs Lisp provides the following advantages:
1. Making small changes/additions requires little programming effort compared to other strongly-typed languages. "You can write a useful command in under a dozen lines"
2. Can test expressions in the Emacs buffer for immediate evaulation. This is similar to how you can test PHP & Python regular expressions at websites such as http://re.dabase.com/
3. As a unique programming language, it's powerful enough to make sense of thousand-line programs.
4. It doesn't crash when run-time bugs are encountered but it does report the errors. Since I don't know the technical details, I wonder how they handle null pointers and the avoidance of data corruption. I would think one would prefer to crash the application then to continue running and corrupting data.
My only concern about the architecture is that every function in a package is visible to other packages. What happened to Encapsulation? Wouldn't these lead to complex dependencies if functions just started referencing functions from other packages at will? Also, I was expecting the article to explain the Model's complexity in its section, "How complex is the Model?". But all it really does is explain how it doesn't support stylessheets, among other features, as in the case of Microsoft Word documents.
Lastly, I did enjoy reading about how it compares & contrasts with Eclipse & Firefox. Although it bashes Eclipse for all the boilderplate code necessary to implement a simple plug-in, from an Eclipse user's standpoint (not from a developer perspective), this is a straight-forward and convenient architecture. And the author took the opportunity to credit Emacs for Firefox's successful architecture since the Emacs project may not be around for too long.
One of the coolest features is its ability to pipeline commands for text to be navigated, searched, organized, trimmed, and sorted all at once. As the article explained, this is possible due to their Model Design of text buffers. Also, it provides support for text terminals while simultaneously managing graphical frames. These are features you can't do with Visual Studio nor Eclipse.
Using the MVC pattern is a natural choice for text editing applications. It proved to be particularly useful in the case of Emacs since their Controller code, in isolation from the Model & View, was almost done entirely in Emacs Lisp. I haven't written code in any language related to Lisp but, apparently, Emacs Lisp provides the following advantages:
1. Making small changes/additions requires little programming effort compared to other strongly-typed languages. "You can write a useful command in under a dozen lines"
2. Can test expressions in the Emacs buffer for immediate evaulation. This is similar to how you can test PHP & Python regular expressions at websites such as http://re.dabase.com/
3. As a unique programming language, it's powerful enough to make sense of thousand-line programs.
4. It doesn't crash when run-time bugs are encountered but it does report the errors. Since I don't know the technical details, I wonder how they handle null pointers and the avoidance of data corruption. I would think one would prefer to crash the application then to continue running and corrupting data.
My only concern about the architecture is that every function in a package is visible to other packages. What happened to Encapsulation? Wouldn't these lead to complex dependencies if functions just started referencing functions from other packages at will? Also, I was expecting the article to explain the Model's complexity in its section, "How complex is the Model?". But all it really does is explain how it doesn't support stylessheets, among other features, as in the case of Microsoft Word documents.
Lastly, I did enjoy reading about how it compares & contrasts with Eclipse & Firefox. Although it bashes Eclipse for all the boilderplate code necessary to implement a simple plug-in, from an Eclipse user's standpoint (not from a developer perspective), this is a straight-forward and convenient architecture. And the author took the opportunity to credit Emacs for Firefox's successful architecture since the Emacs project may not be around for too long.
Wednesday, September 30, 2009
Our Pattern Language (OPL)
Indeed, this is just an overview of a language, OPL, for describing patterns in parallel programming. As the article listed, OPL has the benefit of guiding framework design, providing a consistent method for communicating concepts, and helping newbies become familiarized with parallel programming. For sure, the structure and organization of layers will provide context when we start diving into the more specific parallel programming articles. But for now, this just lists patterns within the OPL framework without describing them.
Tuesday, September 29, 2009
BA Chap.10 - Jikes RVM
Unless one is familiar with how Java Virtual Machines work, this is a difficult read. Even so, the benefits for having a self-hosting JVM doesn't seem apparent. It could be because I didn't fully comprehend the details. But from what I can understand, here are the benefits of Jikes RVM:
1. Simplifies the development model compared to using C/C++.
2. Allows developers to use language features in order to make better optimizations.
3. Helps detect & fix bugs in the JVM.
4. Provides the ability to user better libraries and abstractions.
5. Facilitates communication between the runtime and the application.
It's hard to see these benefits when the article doesn't explicitly mention success stories in industry. Sure they mention that hundreds of researchers in over 100 institutions are part the development community, but that's too vague.
What I wasn't able to understand was what is the difference between self-hosting and metacircularity? According to the article, they mean the same thing. According to Wikipedia, it means,
"A meta-circular evaluator is a special case of a self-interpreter in which the existing facilities of the parent interpreter are directly applied to the source code being interpreted, without any need for additional implementation"
Can anyone provide a better explanation?
Also, I was confused on the discussion of how they bootstrapped Jikes RVM. Are all JVMs written in C considered to be bootstrap JVMs within the context of creating self-hosting JVMs?
Finally, the most surprising thing I found about the article was that metacircular runtime systems have been around since Lisp and Smalltalk were developed. In addition, Just-In-Time compilations and Adaptive optimizations have appeared in Smalltalk since the 1980's. Now they're becoming mainstream with their inclusion in Java, Python, and the .NET framework. Interesting to observe that many of us view these as "new" concepts.
1. Simplifies the development model compared to using C/C++.
2. Allows developers to use language features in order to make better optimizations.
3. Helps detect & fix bugs in the JVM.
4. Provides the ability to user better libraries and abstractions.
5. Facilitates communication between the runtime and the application.
It's hard to see these benefits when the article doesn't explicitly mention success stories in industry. Sure they mention that hundreds of researchers in over 100 institutions are part the development community, but that's too vague.
What I wasn't able to understand was what is the difference between self-hosting and metacircularity? According to the article, they mean the same thing. According to Wikipedia, it means,
"A meta-circular evaluator is a special case of a self-interpreter in which the existing facilities of the parent interpreter are directly applied to the source code being interpreted, without any need for additional implementation"
Can anyone provide a better explanation?
Also, I was confused on the discussion of how they bootstrapped Jikes RVM. Are all JVMs written in C considered to be bootstrap JVMs within the context of creating self-hosting JVMs?
Finally, the most surprising thing I found about the article was that metacircular runtime systems have been around since Lisp and Smalltalk were developed. In addition, Just-In-Time compilations and Adaptive optimizations have appeared in Smalltalk since the 1980's. Now they're becoming mainstream with their inclusion in Java, Python, and the .NET framework. Interesting to observe that many of us view these as "new" concepts.
Saturday, September 26, 2009
Adaptive Object-Model
At first this was a difficult architectural pattern to understand because its' class definitions have a higher level of abstraction (e.g. Entity & EntityType). But after reading about the TypeObject pattern at http://www.comlab.ox.ac.uk/people/jeremy.gibbons/dpa/typeobject.pdf, the Property pattern at http://www.codeproject.com/KB/architecture/AOM_Property.aspx, and Entity Relationships at http://www.codeproject.com/KB/architecture/EntityRelationships.aspx, this made a lot more sense. My suggestion is for developers to get a good grasp on these patterns before they dive into trying to understand AOM.
The first thought that came to my mind was that AOM is pretty much database design. Its like the Entity class is a table that has a foreign key to the EntityType table. But this foreign key is actually a pointer to an instance (or typeObject) of the EntityType class. Data in databases are used by applications at run-time, which is analogous to meta-data being interpreted by AOM architectures. The only distinction the article gives is "The key problem with databases is attaching method to these objects". This leads me to conclude that the TypeObject pattern is more lot database design, but AOM includes interpreting and executing Behaviors and Business Rules.
I recently worked on a sub-system of an application that had the AOM architecture. All an administrator had to do was specify required fields in a form but when I looked at the code, I thought it was unnecessarily complicated. From the UI, it navigated through 3 classes where the implementation would read from the database to figure out what fields to display (e.g. Birth Time), how to display a required field (e.g. should it have an asterisk or a pound sign), and how to behave (Strategy Pattern. Should it throw an error message? If so, what message). The traditional way would've been to implement this statically as a class, but I soon realized how incredibly easy it was to update the form. All I had to do was add a new DB entry! We only provided the System Administrator limited ability to change the meta-data; more specifically, they had the power to change the required fields in a form. But we didn't want them to know that they could, theoretically, include new fields and change their behavior at run-time through simple DB modifications. Providing too much power to users brings the risk of them inadvertently putting the system in an unstable state. If they want a change in behavior, we can simply provide a DB-update script that would reflect the changes without having to recompile the code!
The first thought that came to my mind was that AOM is pretty much database design. Its like the Entity class is a table that has a foreign key to the EntityType table. But this foreign key is actually a pointer to an instance (or typeObject) of the EntityType class. Data in databases are used by applications at run-time, which is analogous to meta-data being interpreted by AOM architectures. The only distinction the article gives is "The key problem with databases is attaching method to these objects". This leads me to conclude that the TypeObject pattern is more lot database design, but AOM includes interpreting and executing Behaviors and Business Rules.
I recently worked on a sub-system of an application that had the AOM architecture. All an administrator had to do was specify required fields in a form but when I looked at the code, I thought it was unnecessarily complicated. From the UI, it navigated through 3 classes where the implementation would read from the database to figure out what fields to display (e.g. Birth Time), how to display a required field (e.g. should it have an asterisk or a pound sign), and how to behave (Strategy Pattern. Should it throw an error message? If so, what message). The traditional way would've been to implement this statically as a class, but I soon realized how incredibly easy it was to update the form. All I had to do was add a new DB entry! We only provided the System Administrator limited ability to change the meta-data; more specifically, they had the power to change the required fields in a form. But we didn't want them to know that they could, theoretically, include new fields and change their behavior at run-time through simple DB modifications. Providing too much power to users brings the risk of them inadvertently putting the system in an unstable state. If they want a change in behavior, we can simply provide a DB-update script that would reflect the changes without having to recompile the code!
Thursday, September 24, 2009
Beautiful Architecture Chap. 9 - JPC: An x86 PC Emulator in Pure Java
Beautiful Architecture Chap. 9 - JPC: An x86 PC Emulator in Pure Java
I find the discussion of emulators vs. virtual machines to be somewhat confusing because the terms "emulation", "virtualization", and "simulation" all seem to be used interchangeably. Given how rapidly technology evolves to produce a solution that has the best of both worlds, we probably won't ever find a hard distinction between an emulator, a simulator, and a virtual machine. Nevertheless, it's important to understand their key differences at the moment and to dive into the architectural details of existing solutions. Here's a list of pros & cons of JPC and Virtual Machines in general.
JPC Pros
1. No dependency on the underlying hardware
- Can virtualize an x86 machine on any host that has a JVM
- Completely isolated from HW & SW platform changes; there's no need to change the OS or to have special hardware
2. JVMs are ubiquitous and considered to be one the most secured virtual machines
- JVMs guards against programming errors
- The 3 layers (JPC, JVM, Hardware) are completely independent from each other since they're made by different companies. Given that each have other general uses, they must have gone through some rigorous testing. Therefore, it's unlikely for a security threat to permeate through all these layers.
JPC Cons
1. Highly dependent of Java
- The process of trying to achieve optimal performance, the development of JPC let to workarounds specific to a Java environment.
- With talks about Sun going to be bought out in near future, Java's destiny is uncertain.
2. Still slower than a VM
- Currently executes code at 10% native speed.
- Article never talked about how it compared in performance with other VMs
VM Pros
1. Paravirtualization eliminates the extra level of indirection by making calls to the Hypervisor (as implied by Dan Orchard's blog).
VM Cons
1. As the article states, "You need hardware that is the same as that being 'virtualized'"
2. More dependency on HW/SW
- Paravirtualization requires changing OS or having the HW provide these capabilities
3. Security holes have been claimed
- Blue Pill & System Management Mode (SMS) Memory Attacks via Intel CPU cache Poisoning
- "HW supported x86 CPU virtualization has security vulnerabilities due to the shared L1/L2 cache of multicore chips"
Neither Pro nor Con
1. Virtualization products are typically designed for speed, not security.
In comparison to other emulators, Bochs (written in C++) needs to have built-in support for different operating system while JPC only needs support from a JVM. However, "JPC has to deal with the extra design restrictions and performance considerations for running under a JVM".
Awana81 pointed out that they didn't mention that it only supports a limited number of OSs as of today. Throughout the article, they celebrate the successful emulation of an x86 computer, which is everywhere, yet they haven't gotten it to boot up a WinXP desktop (which is probably the most common OS nowadays). They were only able to boot up to the command line prompt of DOS, many flavors of Linux, and legacy Windows OSs.
Overall, I can see several reasons why emulators like JPC can be useful. You can test software for mobile devices, embedded system and video game consoles before flashing the code into these devices. Also as described at http://www-jpc.physics.ox.ac.uk/applications_cloud.html , this could provide opportunities for cloud computing on idle desktops as opposed to large datacenters where it can save financial & environmental costs . JPC has partnered with NereusV to provide a way for people to donate CPU idle time of their computers by simply going to a webpage; nothing to be installed. Then, developers push their x86 PC software to these NereusV clients without any action by the host user. This is all done within the confinements of JPC, which adds a security level on top of the Java Applet Sandbox.
In the end, the usage of emulators and VMs boil down to this: virtual machines are mostly used for running different OS environments while emulators are mostly used to emulate embedded, mobile devices.
I find the discussion of emulators vs. virtual machines to be somewhat confusing because the terms "emulation", "virtualization", and "simulation" all seem to be used interchangeably. Given how rapidly technology evolves to produce a solution that has the best of both worlds, we probably won't ever find a hard distinction between an emulator, a simulator, and a virtual machine. Nevertheless, it's important to understand their key differences at the moment and to dive into the architectural details of existing solutions. Here's a list of pros & cons of JPC and Virtual Machines in general.
JPC Pros
1. No dependency on the underlying hardware
- Can virtualize an x86 machine on any host that has a JVM
- Completely isolated from HW & SW platform changes; there's no need to change the OS or to have special hardware
2. JVMs are ubiquitous and considered to be one the most secured virtual machines
- JVMs guards against programming errors
- The 3 layers (JPC, JVM, Hardware) are completely independent from each other since they're made by different companies. Given that each have other general uses, they must have gone through some rigorous testing. Therefore, it's unlikely for a security threat to permeate through all these layers.
JPC Cons
1. Highly dependent of Java
- The process of trying to achieve optimal performance, the development of JPC let to workarounds specific to a Java environment.
- With talks about Sun going to be bought out in near future, Java's destiny is uncertain.
2. Still slower than a VM
- Currently executes code at 10% native speed.
- Article never talked about how it compared in performance with other VMs
VM Pros
1. Paravirtualization eliminates the extra level of indirection by making calls to the Hypervisor (as implied by Dan Orchard's blog).
VM Cons
1. As the article states, "You need hardware that is the same as that being 'virtualized'"
2. More dependency on HW/SW
- Paravirtualization requires changing OS or having the HW provide these capabilities
3. Security holes have been claimed
- Blue Pill & System Management Mode (SMS) Memory Attacks via Intel CPU cache Poisoning
- "HW supported x86 CPU virtualization has security vulnerabilities due to the shared L1/L2 cache of multicore chips"
Neither Pro nor Con
1. Virtualization products are typically designed for speed, not security.
In comparison to other emulators, Bochs (written in C++) needs to have built-in support for different operating system while JPC only needs support from a JVM. However, "JPC has to deal with the extra design restrictions and performance considerations for running under a JVM".
Awana81 pointed out that they didn't mention that it only supports a limited number of OSs as of today. Throughout the article, they celebrate the successful emulation of an x86 computer, which is everywhere, yet they haven't gotten it to boot up a WinXP desktop (which is probably the most common OS nowadays). They were only able to boot up to the command line prompt of DOS, many flavors of Linux, and legacy Windows OSs.
Overall, I can see several reasons why emulators like JPC can be useful. You can test software for mobile devices, embedded system and video game consoles before flashing the code into these devices. Also as described at http://www-jpc.physics.ox.ac.uk/applications_cloud.html , this could provide opportunities for cloud computing on idle desktops as opposed to large datacenters where it can save financial & environmental costs . JPC has partnered with NereusV to provide a way for people to donate CPU idle time of their computers by simply going to a webpage; nothing to be installed. Then, developers push their x86 PC software to these NereusV clients without any action by the host user. This is all done within the confinements of JPC, which adds a security level on top of the Java Applet Sandbox.
In the end, the usage of emulators and VMs boil down to this: virtual machines are mostly used for running different OS environments while emulators are mostly used to emulate embedded, mobile devices.
Wednesday, September 23, 2009
Big Ball of Mud
What's considered a big ball of mud is relative to some degree. Some may consider the code to be spaghetti like, while others may consider it to be a great piece of art. Nevertheless, there are several software architectures that most would agree is a big ball of mess. Why is this so popular? I think the main reason is because it's the easiest, fastest way to get code out the door. Managers don't usually like to invest time & money in making a product architecturally sound. A less common situation is when a company buys several small companies, and they stitch together their respective software products in hopes that it will provide the ultimate product. Unfortunately, this is extremely vulnerable to code duplication. More often than not, businesses should at least consider taking the hit and starting over.
What I particularly liked about this article is that it highlighted the forces that cause a big ball of mud. Sure we all know and complain that architecture takes a back seat to time-to-market demands. But on the flip-side of the equation, premature architecture can be risky since it might consume unnecessary resources and it can "discourage evolution and experimentation". Given today's economy, businesses are in great need of fast Return-On-Investments (ROIs). As the article mentions, what's the point of making your product architecturally beautiful if it's going to miss the market deadline and kill your business? Whether or not it was good style would be a moot point.
Finally, I'm a big believer in giving developers time to prototype before committing to a new project. This is because developers first need to get their hands dirty in order to obtain the domain experience they need to make good architectural decisions. Notice that the same reasoning applies as to why its important to first prototype a product of the Layers architectural style.
What I particularly liked about this article is that it highlighted the forces that cause a big ball of mud. Sure we all know and complain that architecture takes a back seat to time-to-market demands. But on the flip-side of the equation, premature architecture can be risky since it might consume unnecessary resources and it can "discourage evolution and experimentation". Given today's economy, businesses are in great need of fast Return-On-Investments (ROIs). As the article mentions, what's the point of making your product architecturally beautiful if it's going to miss the market deadline and kill your business? Whether or not it was good style would be a moot point.
Finally, I'm a big believer in giving developers time to prototype before committing to a new project. This is because developers first need to get their hands dirty in order to obtain the domain experience they need to make good architectural decisions. Notice that the same reasoning applies as to why its important to first prototype a product of the Layers architectural style.
Monday, September 21, 2009
Beautiful Architecture – Guardian: A Fault-Tolerant Operating System Environment (Chapter 8)
By far, the saddest part was that their Tandem Beer Bust was destroyed! In all seriousness, it seems that the Tandem computers with the Guardian OS, collectively, provided a fault-tolerant environment. Although it highlighted the Guardian having process pairs (a primary and a backup in "hot standby" state) the hardware also gave way to much of this fault-tolerant environment with its multiple processors, multiple disk controllers, and multiple busses as shown on page 177. This provided their biggest distinction with conventional computers in that "no part of the system can fail without bringing down the system". In short, they really just provided redundancy in several areas of the hardware and OS. Redundancy, as we all know, leads to more costs but I was surprised that they didn’t mention the enormous power consumption that it required. If you throw in the fans that were located below the I/O controllers, then that's a lot of juice needed to keep the 6 foot processor cabinets cool. Also, redundancy doesn't ensure that data won't get corrupted if both primary and redundancy components fail.
I didn't really think there were any advantages to their naming conventions. I mean, when you have different formats for unpaired system processes, unpaired user processes, named user processes, and network-visible processes, it just becomes a real burden on the programmer. This lack of consistency leads to more bugs and security holes (as shown by the ability to steal the system's root password) that could ultimately lead to the demise of a system.
I didn't really think there were any advantages to their naming conventions. I mean, when you have different formats for unpaired system processes, unpaired user processes, named user processes, and network-visible processes, it just becomes a real burden on the programmer. This lack of consistency leads to more bugs and security holes (as shown by the ability to steal the system's root password) that could ultimately lead to the demise of a system.
Thursday, September 17, 2009
Layers
When we develop most software systems, I think we subconsciously try to implement them using some variant of the layered structure because it's usually the most straightforward way to think about the problem. And I think we all know that by having many layers, it could introduce inefficiencies in some cases. But I don't think we can anticipate the other liabilities that the article describes until we get stuck during coding. For example, the liability of Cascades of Changing Behavior is something I missed several times in the past, mainly because it's difficult to predict what the implementation of the lower layer will entail. Its not until you're actually coding that you realize you need to make changes in every layer to accommodate errors that need to be propagated to the top (sometimes you do this because the service team wants to view lower layer error information at the GUI level). The "you don't know until you're actually doing it" argument can also be applied to the Unnecessary Work and Difficulty in Establishing Granularity Levels liabilities. I think applying a layers architecture is a good way to start designing, assuming that you can't think of a better architecture up-front. But once these liabilities begin to creep up, one may want to consider refactoring the code to conform to an alternative architecture. Or maybe it can be switched over to a Relaxed Structure like TCP/IP if it's an infrastructure system. As the paper says, "The main reason for this is that infrastructure systems are modified less often than application systems, and their performance is usually more important than their maintainability." One of TCP/IP's biggest philosophical complaints about layering is that it constrains data manipulation functions because optimizations of each layer have to occur separately (http://tools.ietf.org/html/rfc3439#page-7).
On a last note, this paper introduces us with some other architectural patterns such as the Blackboard Pattern, the Refactor Pattern, and the Microkernal Pattern. If you would like to take a closer look at these, check out this link http://www.vico.org/pages/PatronsDisseny.html
On a last note, this paper introduces us with some other architectural patterns such as the Blackboard Pattern, the Refactor Pattern, and the Microkernal Pattern. If you would like to take a closer look at these, check out this link http://www.vico.org/pages/PatronsDisseny.html
Wednesday, September 16, 2009
Beautiful Architecture – Xen and the Beauty of Virtualization (Chapter 7)
Interesting that this article mentions Bochs since I actually worked on a research project that used this emulator a few years ago. Overall, this article clarified several misconceptions I had about virtual machines and did a great job distinguishing between virtualization and paravirtualization. I should point out, though, that Virtual Memory was created to make programming applications easier and to make more efficient use of memory. Not necessarily to "ensure that processes cannot interfere with the data or code of other processes". A system would still need to ensure the integrity of data access in a non-Virtual Memory implementation. And just to briefly correct Chad's statement that "All the operating systems hosted by the hypervisor share the same virtual and physical memory". Though they share the same physical address, the guest OS's have their own virtual addresses and page tables. Each OS would ask the hypervisor if it could make an update in its own page table, and the hypervisor would then make sure it doesn't conflict with the physical address mapping of another OS's page table. The article quotes, "Xen must validate all updates to the page tables, and the kernel must inform the hypervisor when it wants to change any page table".
Tuesday, September 15, 2009
Pipes and Filters
Most of us are familiar with the Pipes & Filters architecture from previous experience with Unix and compiler programming. But it's great to read an article that explicitly states the advantages and disadvantages from using such an architecture with several variations that could be used in different contexts. The pipeline in computer architecture came to my mind quite frequently when I was reading this article but it made me realize how different it actually is. For one, the pipeline stages in computer architecture are not intended to be exchanged or recombined for future enhancements (at least I don't think so). Non-adjacent processing steps DO share information through feedback lines for branch prediction and other features. It doesn't allow different sources of input data (imagine a hacker being able to change the source of data at this level), and it always stores the final results in a single format. What are the similarities? The obvious is that you're moving data from one stage (filter) to another via intermediate hardware logic (pipes). But in both cases, you can also multi-process the steps in parallel. Pipelines in computer architecture are not just trying to process data streams from on step to another; they're also controlling the entire execution flow of a program which probably explains why it's more complex. Each step serves the sole purpose of processing its data as fast as possible (at the nanosecond level) for a very specific context. Filters, on the other hand, are designed to be used in different contexts.
Unfortunately, this is as close as I've been to developing an application that might make use of the Pipes & Filters architecture. But it wasn't even an application; it was a MIPS emulator that I implemented in Verilog.
Unfortunately, this is as close as I've been to developing an application that might make use of the Pipes & Filters architecture. But it wasn't even an application; it was a MIPS emulator that I implemented in Verilog.
Monday, September 14, 2009
Beautiful Architecture Chap. 6 - Data Grows Up
Mainly because of its popularity in the Internet, this article is the highlight of this book (it's the first bullet in the book's back cover). But even so, it's a great read (40 pages!) that shows readers step-by-step the reasoning behind the development of FQL, FBML, & FBJS, which was mainly to control the execution of external applications within the Facebook platform. It goes into great lengths describing how its architecture was molded to provide the data integrity that users expect. Yet, it has received a lot of criticism regarding their general approach to the use of people's info over the years.
Although the platform's API, FQL, FBML, &FBJS allows Facebook to restrict the usage of user data by third-party apps, the inverse doesn't seem to apply as demonstrated by their launching of Beacon in late 2007. Facebook can obtain user activity from external applications and post them in news feed. Users can deny confirmations for publishing information provided by Beacon, but there's "no option to prevent Facebook from storing and using information sent by Beacon". If they do decide to give users this option, it should be a fairly straightforward implementation; all they would need are the $user and $app_id parameters from the user. Considering that numerous security holes that have been discovered, users have a right to prevent Facebook from storing such info.
Here are some examples taken from http://en.wikipedia.org/wiki/Criticism_of_Facebook:
"On February 24, 2006, a pair of users exploited a cross-site scripting (XSS) hole on the profile page and created a fast-spreading worm, loading a custom CSS file on infected profiles that made them look like MySpace profiles."
"On April 19, 2006, a user was able to embed an iframe into his profile and load a custom off-site page featuring a streaming video and a flash game from Drawball."
" In July 2007, Adrienne Felt, an undergraduate student at the University of Virginia, discovered a cross-site scripting (XSS) hole in the Facebook Platform that could inject JavaScript into profiles, which was used to import custom CSS and demonstrate how the platform could be used to violate privacy rules or create a worm."
" On March 26, 2006, a user was able to embed JavaScript in the "Hometown" field of his profile which imported his custom CSS."
Notice how most of these occurred between 2-3.5 years ago so I think we can safely assume that Facebook has corrected most these. Nevertheless, Facebook needs to think beyond its own architecture for preventing other apps from compromising user data and be humble enough to realize that they can also, indirectly, be the source for data misusage. FBML & FBJS are great solutions that give them the flexibility to patch security holes in other parts of the platform while giving external apps the ability to run dynamic content. But we all know that no system is ever 100% secure.
Although the platform's API, FQL, FBML, &FBJS allows Facebook to restrict the usage of user data by third-party apps, the inverse doesn't seem to apply as demonstrated by their launching of Beacon in late 2007. Facebook can obtain user activity from external applications and post them in news feed. Users can deny confirmations for publishing information provided by Beacon, but there's "no option to prevent Facebook from storing and using information sent by Beacon". If they do decide to give users this option, it should be a fairly straightforward implementation; all they would need are the $user and $app_id parameters from the user. Considering that numerous security holes that have been discovered, users have a right to prevent Facebook from storing such info.
Here are some examples taken from http://en.wikipedia.org/wiki/Criticism_of_Facebook:
"On February 24, 2006, a pair of users exploited a cross-site scripting (XSS) hole on the profile page and created a fast-spreading worm, loading a custom CSS file on infected profiles that made them look like MySpace profiles."
"On April 19, 2006, a user was able to embed an iframe into his profile and load a custom off-site page featuring a streaming video and a flash game from Drawball."
" In July 2007, Adrienne Felt, an undergraduate student at the University of Virginia, discovered a cross-site scripting (XSS) hole in the Facebook Platform that could inject JavaScript into profiles, which was used to import custom CSS and demonstrate how the platform could be used to violate privacy rules or create a worm."
" On March 26, 2006, a user was able to embed JavaScript in the "Hometown" field of his profile which imported his custom CSS."
Notice how most of these occurred between 2-3.5 years ago so I think we can safely assume that Facebook has corrected most these. Nevertheless, Facebook needs to think beyond its own architecture for preventing other apps from compromising user data and be humble enough to realize that they can also, indirectly, be the source for data misusage. FBML & FBJS are great solutions that give them the flexibility to patch security holes in other parts of the platform while giving external apps the ability to run dynamic content. But we all know that no system is ever 100% secure.
Friday, September 11, 2009
Excerpts From Christopher Alexander
Since these excerpts were intended to describe patterns in the architecture of physical structures, here are my two-cents on how they would or would not apply in the software domain.
"On no account place buildings in the places which are most beautiful. In fact, do the opposite. Consider the site and its buildings as a single living eco-system. Leave those areas that are the most precious, beautiful, comfortable, and healthy as they are, and build new structures in those parts of the site which are least pleasant now."
Does this mean we shouldn't put a piece of functionality on the best part of an existing platform because it might cover up its attractiveness? Is this principle suggesting the motto "If it's not broken, don't fix it" ? Don't agree this principle applies to software because if we're trying to cover up some classes, for example through the use of the façade pattern, then we're trying to simplify the overall functionality of the system. And this doesn't mean you can no longer use the covered up classes because we promote extensions in object-oriented design. In the case of buildings, once you cover up the best part of the land with a building, you pretty much can't take advantage of it. Now this principle does have a good reason for building on top of the worst part of a platform; it may force developers to refactor crappy code while adding functionality. The fact of the matter is that once a developer hacks some code together, we shouldn't expect it to get fixed anytime soon unless you have a disciplined team like the guys from Design Town who mark their "fudges". Many managers won't invest resources to refactor code that "already works".
"Unless the spaces in a building are arranged in a sequence which corresponds to their degrees of privateness, the visits made by strangers, friends, guests, clients, family will always be a little awkward"
Does this mean we should develop an application with the right degree of privacy levels or else it will be awkward to use/extend from? Well, encapsulation is supposed to provide us with this ability so that we don't change the state of a system through some unsafe method. In terms of actual usage, a user will certainly be annoyed if an application has unnecessary levels of privacy restrictions while a federal agent would feel insecure using an application that does not provide encryption.
"When they have a choice, people will always gravitate to those rooms which have light on two sides, and leave the rooms which are lit only from one side unused and empty". Software modules will be used if they're multiple channels for communicating with them but this may not actually be ideal.
Does this mean we should develop software modules that provide more than one way to communicate with it? If so, this definitely does not apply to software because you rather provide a single, consistent interface that would enforce communication integrity as described in ArchJava. Users would also prefer a single, consistent method for using a system. In software, simplification is king. The principle of adding more "windows" can make a system unnecessarily complicated.
"On no account place buildings in the places which are most beautiful. In fact, do the opposite. Consider the site and its buildings as a single living eco-system. Leave those areas that are the most precious, beautiful, comfortable, and healthy as they are, and build new structures in those parts of the site which are least pleasant now."
Does this mean we shouldn't put a piece of functionality on the best part of an existing platform because it might cover up its attractiveness? Is this principle suggesting the motto "If it's not broken, don't fix it" ? Don't agree this principle applies to software because if we're trying to cover up some classes, for example through the use of the façade pattern, then we're trying to simplify the overall functionality of the system. And this doesn't mean you can no longer use the covered up classes because we promote extensions in object-oriented design. In the case of buildings, once you cover up the best part of the land with a building, you pretty much can't take advantage of it. Now this principle does have a good reason for building on top of the worst part of a platform; it may force developers to refactor crappy code while adding functionality. The fact of the matter is that once a developer hacks some code together, we shouldn't expect it to get fixed anytime soon unless you have a disciplined team like the guys from Design Town who mark their "fudges". Many managers won't invest resources to refactor code that "already works".
"Unless the spaces in a building are arranged in a sequence which corresponds to their degrees of privateness, the visits made by strangers, friends, guests, clients, family will always be a little awkward"
Does this mean we should develop an application with the right degree of privacy levels or else it will be awkward to use/extend from? Well, encapsulation is supposed to provide us with this ability so that we don't change the state of a system through some unsafe method. In terms of actual usage, a user will certainly be annoyed if an application has unnecessary levels of privacy restrictions while a federal agent would feel insecure using an application that does not provide encryption.
"When they have a choice, people will always gravitate to those rooms which have light on two sides, and leave the rooms which are lit only from one side unused and empty". Software modules will be used if they're multiple channels for communicating with them but this may not actually be ideal.
Does this mean we should develop software modules that provide more than one way to communicate with it? If so, this definitely does not apply to software because you rather provide a single, consistent interface that would enforce communication integrity as described in ArchJava. Users would also prefer a single, consistent method for using a system. In software, simplification is king. The principle of adding more "windows" can make a system unnecessarily complicated.
Thursday, September 10, 2009
Beautiful Architecture (Chap. 5) - Resource-Oriented Architectures
It's great to know that there already exists several ROA implementations such as Ruby on Rails, NetKernel, Django, etc. because this article has convinced me that RESTful architectures are the future. Although my understanding of Web architecture is limited and I've never heard of ROA, the approach of using logical named interfaces would allow us to not worry about concrete implementations and give us the reassurance that it will scale as new technologies come and go. This is because we can use the same name (that's easy to remember) to retrieve the same data in different structural forms such as text, images, or in applications as shown in Figure 5-5 of page 101. In addition, by restricting REST to 4 variables, it makes it easy to design any operation imaginable which leads to a more scalable, flexible, and extensible architecture.
I remember going through the steep learning curve of implementing a Java application that had SOAP messages with MTOM attachments and had to figure out how to write-up a WSDL; it was unnecessarily brittle. Sure there are several online examples of using web services to send SOAP messages, but when you run into complex issues, you may have understand the nuts & bolts of it.
I remember going through the steep learning curve of implementing a Java application that had SOAP messages with MTOM attachments and had to figure out how to write-up a WSDL; it was unnecessarily brittle. Sure there are several online examples of using web services to send SOAP messages, but when you run into complex issues, you may have understand the nuts & bolts of it.
Tuesday, September 8, 2009
Although ArchJava may be too stringent to be applicable in many scenarios, it's definitely a great extension to use when starting on a new project with multiple developers. First, it encourages team members to think about designing to interfaces via connections as opposed to concrete classes. Second, it attracts programmers to think about the problem in a hierarchical manner, which often leads to a simpler design. Just look at how they first broke up the Aphyds into a simple Model and View architecture. They later broke up the View into subcomponents such as CircuitViewer, PlaceRouteViewer, ChannelRouteViewer, etc, and then broke up the AphydsModel. They didn't worry about the details until they needed to. And finally, it prevents programmers from furtively making references to classes that clearly violate the Law of Demeter. In a previous game project that I worked on with a team, it often took me a few hours to figure out root cause of a bug because there were references to model data in at least 10 different classes.
Interesting that the article discussed how they decided to persistent components for the entire execution of the program instead of having a dynamically changing architecture due to screen refresh issues. We also encountered a similar issue when the game was restarted because the code would create new instances of the model data while the View continued to hold references to the old model data. We simply decided to re-initialize the model data.
Overall, the idea behind it is great if you want to make a software architecture explicit and want to avoid unnecessary references that can lead to bugs. However, I don't think many would use it for a couple of reasons. First, its restricted to Java. Sure you can create a version of this in .NET. But what would you call it? ArchNet? And who would take the time to do this? From looking at the ArchJava home page, it seems that they stopped working on this since June 2005 so I wouldn't count on the original team. More importantly, I don't think architects would take the time to learn the ArchJava syntax since they would pretty much have to write a good chunk of code, which can be cumbersome. Maybe if they built a GUI on top of this that would automatically generate the method signatures, connections, etc., then I think there's a better chance architects would use it.
Interesting that the article discussed how they decided to persistent components for the entire execution of the program instead of having a dynamically changing architecture due to screen refresh issues. We also encountered a similar issue when the game was restarted because the code would create new instances of the model data while the View continued to hold references to the old model data. We simply decided to re-initialize the model data.
Overall, the idea behind it is great if you want to make a software architecture explicit and want to avoid unnecessary references that can lead to bugs. However, I don't think many would use it for a couple of reasons. First, its restricted to Java. Sure you can create a version of this in .NET. But what would you call it? ArchNet? And who would take the time to do this? From looking at the ArchJava home page, it seems that they stopped working on this since June 2005 so I wouldn't count on the original team. More importantly, I don't think architects would take the time to learn the ArchJava syntax since they would pretty much have to write a good chunk of code, which can be cumbersome. Maybe if they built a GUI on top of this that would automatically generate the method signatures, connections, etc., then I think there's a better chance architects would use it.
Monday, September 7, 2009
Beautiful Architecture Ch 4: Making Memories
This is the first article that shows how a team architects a software solution for a real customer. I particularly enjoyed how it starts off by thoroughly describing the problem domain and the workflow for producing high-quality pictures. With this in mind, the team was able to focus on only those architectural facets that were relevant to their problem-space as opposed to making assumptions about what the product solution will need, which would be wasteful. Figure 4-1 on page 64 pretty much sums it up.
A benefit of reading an article like this is that it introduces me to existing concepts, technologies, and tools that could be useful when architecting a future project. For example, the mention of Spring and OSGi frameworks (can be used for encapsulating & declaring module dependencies) sparked my curiosity to learn more about them. And I can consider using Graphviz and Java NIO for a current project at my job.
One of the things that stood out was that the author's team from Advanced Technologies Integration (ATI) used Lean Software development. According to Wikipedia, it is "a translation of lean manufacturing principles and practices to the software development domain." Manufacturing principles can applied in the software domain? Six months ago, I attended a Lean Six-Sigma course but the instructor was unable to provide concrete examples of how this is applied in the software world. It turns out that Lean Software Development is a form of Agile that makes use of these principles but just calls them differently. For those that are interested, here are some examples from Wikipedia:
Waste in Software Development
* unnecessary code and functionality
* delay in the software development process
* unclear requirements
* bureaucracy
* slow internal communication
Lean Software Development Tools
* Seeing waste
* Value stream mapping
* Set-based development
* Pull systems
* Queuing theory
* Motivation
* Measurements
A benefit of reading an article like this is that it introduces me to existing concepts, technologies, and tools that could be useful when architecting a future project. For example, the mention of Spring and OSGi frameworks (can be used for encapsulating & declaring module dependencies) sparked my curiosity to learn more about them. And I can consider using Graphviz and Java NIO for a current project at my job.
One of the things that stood out was that the author's team from Advanced Technologies Integration (ATI) used Lean Software development. According to Wikipedia, it is "a translation of lean manufacturing principles and practices to the software development domain." Manufacturing principles can applied in the software domain? Six months ago, I attended a Lean Six-Sigma course but the instructor was unable to provide concrete examples of how this is applied in the software world. It turns out that Lean Software Development is a form of Agile that makes use of these principles but just calls them differently. For those that are interested, here are some examples from Wikipedia:
Waste in Software Development
* unnecessary code and functionality
* delay in the software development process
* unclear requirements
* bureaucracy
* slow internal communication
Lean Software Development Tools
* Seeing waste
* Value stream mapping
* Set-based development
* Pull systems
* Queuing theory
* Motivation
* Measurements
Wednesday, September 2, 2009
Beautiful Architecture Chapter 2
This paper seems to argue that one SHOULD focus on functionality initially when designing the architecture of a system as given in their Design Town example,
"Early in the design process, we established the main areas of functionality (these included the core audio path, content management, and user control/interface)"
but that you should "defer design decisions until you have to make them". Since there's only so much you can know upfront, I think a general understanding of the functionality would be sufficient to commence a simple architecture. Because of its simplicity, you can then focus on adding the quality attributes that were discussed in Chapter 1 of Beautiful Architecture. Assuming these first two steps were done correctly, you've now created a superstar architecture that could tack on new functionality with ease. Sounds like a cookbook recipe, doesn't it? But aren't we all trying to come up with a recipe for architectural design that works? At the very least, this provides a reference to work off of when you don't know where to begin or which paper's recipe to follow.
An interesting aspect of the Metropolis that I can relate to is when it said,
"the Metropolis started out as a series of separate prototypes that got tacked together when they should have been thrown away. The Metropolis was actually an accidental conurbation. When stitched together, the code components had never really fit together properly. Over time, the careless stitches began to tear, so the components pulled against one another and caused friction in the codebase, rather than working in harmony."
I'm at a company that has the constant habit of buying other small companies. Business leaders think you can just combine their software solutions and they'll somehow "magically" work together. The problem is that interoperability in some industries, like Healthcare, is harder than others (which explains why we don't yet have an integrated, National Healthcare System). Then I'm put in a situation where I'm adding new functionality in 5 different places from 3 different products using C++, C#, Java, and some other weird language. What a mess! So how can a business invest in the future through software reconstruction and, at the same time, deliver short-term products to keep itself financially healthy?
In Design Town, they mentioned that developers would mark technical debts on "fudges" that would be scheduled for correction at a later revision but how likely is that to happen in a business where everything is a priority that needs to get done now? I would expect most teams to ignore these fudges.
"Early in the design process, we established the main areas of functionality (these included the core audio path, content management, and user control/interface)"
but that you should "defer design decisions until you have to make them". Since there's only so much you can know upfront, I think a general understanding of the functionality would be sufficient to commence a simple architecture. Because of its simplicity, you can then focus on adding the quality attributes that were discussed in Chapter 1 of Beautiful Architecture. Assuming these first two steps were done correctly, you've now created a superstar architecture that could tack on new functionality with ease. Sounds like a cookbook recipe, doesn't it? But aren't we all trying to come up with a recipe for architectural design that works? At the very least, this provides a reference to work off of when you don't know where to begin or which paper's recipe to follow.
An interesting aspect of the Metropolis that I can relate to is when it said,
"the Metropolis started out as a series of separate prototypes that got tacked together when they should have been thrown away. The Metropolis was actually an accidental conurbation. When stitched together, the code components had never really fit together properly. Over time, the careless stitches began to tear, so the components pulled against one another and caused friction in the codebase, rather than working in harmony."
I'm at a company that has the constant habit of buying other small companies. Business leaders think you can just combine their software solutions and they'll somehow "magically" work together. The problem is that interoperability in some industries, like Healthcare, is harder than others (which explains why we don't yet have an integrated, National Healthcare System). Then I'm put in a situation where I'm adding new functionality in 5 different places from 3 different products using C++, C#, Java, and some other weird language. What a mess! So how can a business invest in the future through software reconstruction and, at the same time, deliver short-term products to keep itself financially healthy?
In Design Town, they mentioned that developers would mark technical debts on "fudges" that would be scheduled for correction at a later revision but how likely is that to happen in a business where everything is a priority that needs to get done now? I would expect most teams to ignore these fudges.
Monday, August 31, 2009
Field Guide to Boxology
I found this paper very interesting because it pretty much provides "a checklist of topics to consider, thereby setting expectations for elements to include in the design". This could be a good reference whenever we're given a very general problem to solve. Also, I feel the "vocabulary used to describe styles more precise and shareable among software architects" is probably the most important thing that comes out of this classification; similar to what Design Patterns provides us.
Considering that this paper was published in 1996, why isn't there a popular book that transcends these concepts for decades to come? Maybe Ralph Johnson can get the Gang of Four team back together and write one for Architecture Styles. Or maybe they already did ...
I'm familiar with the Unix Pipes & Filters and Pipeline data flow styles but did anyone else find it weird to see the word "Transducer" as a constituent component? As a hardware guy, it’s obviously a device that transforms one form of energy into another like a thermometer or a microphone. In the context of the paper, it’s a dataflow network style where, "components are elements that asynchronously transform input into output with minimal retained state". Never heard of this term used in the software world.
In Table 2, they make the distinction between write-time & compile time. Aren't these the same? Also, can anyone tell me what's the difference between invocation & run-time? They pretty much sound the same to me.
And finally, did anyone find it annoying that they made several incorrect references to Table 1 when they meant Table 2 and vice-versa? I was worried I had read something for half-an-hour and not understood a thing!
Considering that this paper was published in 1996, why isn't there a popular book that transcends these concepts for decades to come? Maybe Ralph Johnson can get the Gang of Four team back together and write one for Architecture Styles. Or maybe they already did ...
I'm familiar with the Unix Pipes & Filters and Pipeline data flow styles but did anyone else find it weird to see the word "Transducer" as a constituent component? As a hardware guy, it’s obviously a device that transforms one form of energy into another like a thermometer or a microphone. In the context of the paper, it’s a dataflow network style where, "components are elements that asynchronously transform input into output with minimal retained state". Never heard of this term used in the software world.
In Table 2, they make the distinction between write-time & compile time. Aren't these the same? Also, can anyone tell me what's the difference between invocation & run-time? They pretty much sound the same to me.
And finally, did anyone find it annoying that they made several incorrect references to Table 1 when they meant Table 2 and vice-versa? I was worried I had read something for half-an-hour and not understood a thing!
Software Architecture in Practice: Chapter 4
I'm not sure if conceptual integrity is a good phrase for describing consistency in a system's design, but I absolutely agree that it's better to have uniformity that to have "certain anomalous features and improvements"; and it seems that most people agree. The difficulty with this is that you can have a situation where several team members will aggressively hold on to their ideas that will cause a debate for hours. In which case, an assigned architect would be helpful to make the final call. So I would also add to expect wasted hours in effort to the quote,
"make the architect available. If no one is identified with that role, it is a sign that conceptual integrity may be lacking"
If Buildability is the quality that, among other things, measures how much parallelism can occur in development, then conforming to the object-oriented principle of designing to interfaces is crucial. I've been a part of several projects where teams don't do this and we end up with spaghetti code that takes several hours to make a small change.
Finally, the author states that buildability also has to do with how much knowledge the team has about the problem.
"A design that casts a solution in terms of well-understood concepts is thus more buildable than one that introduces new concepts"
Although I agree with this, a team has to start somewhere. A company can buy another company that has the expertise of a domain, or they can gain it through years of experience of selling solutions of this domain. In which case, their ability to deliver a solution should be expected to be delayed. It seems that when companies invest on pet projects to get expertise on some domain is when they're most successful (think Google). It might be because they're not pressured to release a product any time soon and, therefore, aren't forced to compromise architectural qualities that will come back to haunt them later. Any thoughts?
"make the architect available. If no one is identified with that role, it is a sign that conceptual integrity may be lacking"
If Buildability is the quality that, among other things, measures how much parallelism can occur in development, then conforming to the object-oriented principle of designing to interfaces is crucial. I've been a part of several projects where teams don't do this and we end up with spaghetti code that takes several hours to make a small change.
Finally, the author states that buildability also has to do with how much knowledge the team has about the problem.
"A design that casts a solution in terms of well-understood concepts is thus more buildable than one that introduces new concepts"
Although I agree with this, a team has to start somewhere. A company can buy another company that has the expertise of a domain, or they can gain it through years of experience of selling solutions of this domain. In which case, their ability to deliver a solution should be expected to be delayed. It seems that when companies invest on pet projects to get expertise on some domain is when they're most successful (think Google). It might be because they're not pressured to release a product any time soon and, therefore, aren't forced to compromise architectural qualities that will come back to haunt them later. Any thoughts?
Sunday, August 30, 2009
Beautiful Architecture - Chapter 1
I disagree with the author's statement,
"That's right -- the first concern of a software architect is not the functionality of the system",
because a high-level understanding of a system's functionality is usually needed to drive quality concerns. With any system, one has to consider the quality attribute trade-offs so depending on the functionality of the system, one would choose one trade-off over another. I agree that decomposing the system into functional requirements is more difficult but I'm arguing that you need to have some idea of the system's functionality before you begin. The author even contradicts himself when he gives the example,
"Or perhaps our application is a web-based telephone and we need to make the phone 'ring'. If you need to send true asynchronous events from the server to the web page to satisfy performance requirements, an architecture based on servlets might be more testable and modifiable."
This is an example of knowing some functionality about the system, and then making an architectural decision based on it. I'm not saying that all functional requirements should be done before quality requirements. I'm saying that you should start with a high-level understanding, then dig into the quality requirements, then do the functional requirements, and then repeat the same process. It should be an iterative process.
@Richard Young. I agree that business needs often drive the architecture of a solution but, unfortunately, sometimes businesses do not understand the technical ramifications of making certain decisions. Many times, they'll ship out rushed code in order to win in the market (without considering other architectural alternatives), but that usually leads to more defects in the field and code that's expensive to maintain in the long run.
@Michael Davidson. I'm not sure if I agree with the 'Minimize Mechanisms' philosophy. Although I agree that you shouldn't waste time and effort trying to search for the 'best solution', one shouldn't just settle for the first solution that meets their needs. If developers could spend just a few more cycles investigating other solutions (my rule of thumb is no more than 3), they might encounter something that's even BETTER than one would've imagined. It could also save one the embarrassment of presenting their solution to an audience that asks them why they didn't consider the 'BETTER' solution (audience knows the better solution because they googled it ! ).
@AWANA81. I do think that all developers should have some knowledge of the software architecture of the system because they would be more likely to bring up critical issues than if there were confined into their own little world. Also, Ralph Johnson mentioned that for a small team of about 4, it doesn't make sense to have a dedicated architect. This is a case where it's crucial for all developers to know the architecture well.
"That's right -- the first concern of a software architect is not the functionality of the system",
because a high-level understanding of a system's functionality is usually needed to drive quality concerns. With any system, one has to consider the quality attribute trade-offs so depending on the functionality of the system, one would choose one trade-off over another. I agree that decomposing the system into functional requirements is more difficult but I'm arguing that you need to have some idea of the system's functionality before you begin. The author even contradicts himself when he gives the example,
"Or perhaps our application is a web-based telephone and we need to make the phone 'ring'. If you need to send true asynchronous events from the server to the web page to satisfy performance requirements, an architecture based on servlets might be more testable and modifiable."
This is an example of knowing some functionality about the system, and then making an architectural decision based on it. I'm not saying that all functional requirements should be done before quality requirements. I'm saying that you should start with a high-level understanding, then dig into the quality requirements, then do the functional requirements, and then repeat the same process. It should be an iterative process.
@Richard Young. I agree that business needs often drive the architecture of a solution but, unfortunately, sometimes businesses do not understand the technical ramifications of making certain decisions. Many times, they'll ship out rushed code in order to win in the market (without considering other architectural alternatives), but that usually leads to more defects in the field and code that's expensive to maintain in the long run.
@Michael Davidson. I'm not sure if I agree with the 'Minimize Mechanisms' philosophy. Although I agree that you shouldn't waste time and effort trying to search for the 'best solution', one shouldn't just settle for the first solution that meets their needs. If developers could spend just a few more cycles investigating other solutions (my rule of thumb is no more than 3), they might encounter something that's even BETTER than one would've imagined. It could also save one the embarrassment of presenting their solution to an audience that asks them why they didn't consider the 'BETTER' solution (audience knows the better solution because they googled it ! ).
@AWANA81. I do think that all developers should have some knowledge of the software architecture of the system because they would be more likely to bring up critical issues than if there were confined into their own little world. Also, Ralph Johnson mentioned that for a small team of about 4, it doesn't make sense to have a dedicated architect. This is a case where it's crucial for all developers to know the architecture well.
Wednesday, August 26, 2009
Subscribe to:
Posts (Atom)