scea – decomposition strategies example – part 1

Decomposition strategies are described in the Cade & Sheil Sun Certified Architect (SCEA) study guide.  Or maybe I should say the Oracle Certified Master, Java EE 5 Enterprise Architect (OCMJEA) now.  When I read the study guide and and took SCEA part 1, I found this to be very straightforward.  Then I read a thread in the CodeRanch certification forum where two people asked for tutorials or examples.  I searched online and didn’t find anything so decided to write one.

What is decomposition?

Decomposition is taking a big thing and turning into a bunch of smaller things.  In software architecture/design, this is used in designing a system.  Suppose you have 1000 classes.  How do you separate them into projects and packages that are manageable.  Decomposition can also be thought of as organizing or categorizing.  (Thanks Scott! This is a good way to put it.)

Types of decomposition

Case & Sheil list the following types of decomposition.  It is common not to use all groups in the same system.

  1. Layering or Distribution – layering refers to layering of the system and distribution refers to distribution of resources.  While the book treats these as one category a large system may do layering within a particularly large distribution area.  For example, distribution may go by database vs application server.  Then layering may happen within the application server.
  2. Exposure, Functionality or Generality – exposure refers to black box vs white box type exposure on several levels.  Functionality is about the business domain  (and something we often think about when designing packages.)  Generality is about reuse between systems.
  3. Coupling and Cohesion or Volatility – these should be familiar to any developer.  Low coupling and high cohesion insulate packages.  And keeping the things you expect to change often away from the other things makes maintenance cheaper.
  4. Configuration – when environment/outside things change independently of other things, it makes sense to isolate them.
  5. Planning and Tracking or Work Assignment – when done with everything else, further separating by project management concerns makes sense.  Especially when teams are from different organizations.

Example

Suppose I have the following things in my sandwich shop.  We want to decompose the list in at least two passes so we have no more than 5 items in a category at the end. How you could decompose the list. What strategy would you use first? Why? What would you do next?

  • chicken
  • coupon
  • fork
  • knife
  • lettuce
  • gift card
  • mayonnaise
  • mustard
  • pickle
  • onion
  • paper cup
  • paper receipt
  • pen
  • roast beef
  • roll
  • rye bread
  • spoon
  • tomato
  • turkey
  • wheat bread
  • white bread
  • wrap

Answer

Check part 2 for my answer with explanation.  If you want to take a stab at it – either before or after I’ve posted the answer – go for it.  There is more than one correct answer.  If you post your answer as a comment in this thread, I will give my thoughts on it.  If you post it in the CodeRanch/JavaRanch thread, you may get feedback from others as well.

restoring my iBrick to an iPad

This week, I updated my iPad to OS 3.2.2. It didn’t go well.

What happened:

  1. Plugged in iPad to laptop.
  2. iTunes noted there was an OS update and suggested I backup the iPad before applying it.  I did.  Whew!  This turned out to be a blessing.
  3. Selected option to update.
  4. Got error that could not update.  With error code 14. Apple lists the error codes which is nice.
  5. Tried again but iTunes said my iPad needed to be restored to factory state to work again.  Not happy at this point.
  6. Got a different error code on restore.  Now really nervous.  Tried unplugging and replugging USB.  Seemed to help.
  7. Restore worked

Ok now I’m “restored” to factory settings.  How do I get back to using the iPad.

  1. Synced with iTunes.  This gave me most system settings and some data back.  (It didn’t put my password back, but that was the only thing noticeably missing.)
  2. Most of my apps aren’t here at this point and they have data of their own.  I’m a little nervous at this point.
  3. iTunes as the list of apps that were installed, but I don’t see an easy way to put them back.
  4. Went through the app store and re-downloaded them one by one.  At least iTunes recognized they were bought (thanks to an up to date backup) and didn’t charge me again.
  5. Tried some of the apps.  They do still have the data from the iTunes sync.  That means iTunes does sync data even if the app it goes with isn’t currently installed.

Summary

  • Best thing – I didn’t lose any data
  • Worst thing – re-downloading each app is tedious.  Can’t iTunes send a list to the iPad and have the app store download everything on that list?

Memo: Avoid Functions in Database Queries

The most common type of questions in the JavaRanch JDBC forum tends to be about improving performance in a database (that, and “Where can I download a JDBC Driver?”). While remote trouble-shooting performance issues can be tricky, we often spot issues with the presented queries and offer alternatives to improve performance. One issue I see from time to time is the use of database built-in functions in database queries. In general, these should be avoided at all costs for commonly-executed queries, especially ones that could trigger the function to be applied to every record in a table. This article will address this issue of using functions in database queries in more detail and provide explanations and tips for avoiding them in the future.

1. Throwing away indexes

By default, databases search an entire table for records. The purpose of indexes, created automatically by some DBMS systems, is to allow records to be retrieved faster. Using Big O notation, a sorted set of records can find an item within a range in O(log(n)) while an unsorted set would have to search the entire table, or O(n). For hash searches on a specific key, the search time is near O(constant) for properly balanced data structures.

Developers can create indexes on multiple columns in a table, but they have no direct control over how and when they are used. It is the job of the DBMS query optimizer to apply what it thinks are the best indexes at the time the query is requested. Queries that apply a function to a column in a database will likely throw away any index that the query optimizer could take advantage of to search the table, resulting in a full-table scan every time the table is queried. If you are lucky and your table only contains a few dozen records, this issue might not be noticeable, but for the rest of us, this could pose a serious problem. While there are some DBMSs, Oracle being one of them, that support function-based indexes, but they are far from standard practice.

2. Goodbye Portability

My biggest issue with functions, like any database-specific feature, is the fact that they are database specific features! Once you write a query that takes advantage of a specific function, porting your application to a different database system becomes much more difficult. Oftentimes, functions are used because there is a muddling of the data, application, and presentation layer. I have seen developers use database-specific functions to format data (most commonly, dates) from SELECT queries that are transmitted from JDBC directly to the user. If you have a strong mid-tier platform like Java, it is better to leverage the formatting functions within the language, not database-specific ones, to present data to the user.

Porting an application to a different database is non-trivial at best, but the use of database-specific functions will make the job much more difficult. And to those developers out there who often comment that switching databases never happens, it does. I’ve done it. And it’s not for the faint of heart.

3. Slow if used incorrectly

There are correct ways to use functions in database queries that are often overlooked when writing the query. For example, compare the following two MySQL-based queries, both of which search for orders placed on February 15, 2010 and use built-in functions:

SELECT * FROM Widgets WHERE DATE_FORMAT(orderDate,"%Y-%m-%d") = '2010-02-15';
SELECT * FROM Widgets WHERE orderDate = (CAST '2010-02-15' as DATETIME);

First, question is, are they equivalent? The answer is no, but let’s skip that for now and discuss performance. Which is likely to perform better on a database that contains a tree-based index on Widgets.orderDate?

Give up? The second query, of course! The second query applies a function to a constant, and most database query analyzers are intelligent enough to only apply this function once. It then uses the range index to find the records in Log(n) time. On the other hand, the first query performs a function call on every record in the table and therefore ignores the index – resulting in a slow table scan.

As for accuracy, if orderDate is a DATETIME, the second query will return all the results placed only at midnight on February 2nd (2010-02-15 00:00:00) while the second query will return all results placed during the entire day. No worries – there is an easy fix that still uses the index on orderDate for optimal performance:

SELECT * FROM Widgets WHERE orderDate >= (CAST '2010-02-15' as DATETIME)
     AND orderDate < (CAST '2010-02-16' as DATETIME);

Even though this adds a second parameter to the search, the sorted index can be applied to both.

Final Thoughts

Like many things in the world, database functions are necessary evil that are required to solve certain problems. The goal shouldn’t be to never use them, but to keep using them to a minimum. One common solution, if the function is being applied to a column repeatedly, is to denormalize the data and add a new column containing the value of the original column with the function applied to it. This is equivalent to how a function-based index works, for databases that do not have this feature built-in. The only overhead is the cost of maintaining the value in the new column each time the original value is updated, although since reads are more common than writes, this is often easy in practice. I am aware some developers have issues with denormalized data, but it is often necessary on large tables with queries that can run for minutes or even hours.

In the previous example, if searching on specific single dates is extremely common, the developer could add an orderDateSTR column that contains strings such as ‘2010-02-15’. A hash index could then be built on the column which would allow searches for single dates to be accomplished in near constant time. Granted, this is not useful for range queries, but would be useful in situations where single date searching needed to be fast on large data sets.