Ads by Google

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

トランザクション管理の複雑性を克服する パート1

トランザクション管理の複雑性を克服する パート1

The Rational Edge

トランザクション管理の複雑性を克服する パート1
トランザクション・コーディネーション・サービス

BioLogic Software Consulting, LLC
主任ソフトウェアアーキテクト
Benjamin Lieberman

2006/8/23

The Rational Edgeより:サービス指向のインフラの中で発生するビジネストランザクションは非常に複雑だ。それは、サービスが非同時的で、さまざまな形態を取り、分散し、不透明な場合が多いためだ。本稿は、トランザクション・コーディネーションサービスがこの複雑性をどのように調整し、管理するかについて説明する。

  トランザクションは、業務上のあらゆるやりとりに必要なものだ。トランザクションは、特定の業務活動が隅々まで適切に遂行されるのを保証する目的で存在する。どこか1カ所でも不備が発生したら、データの一貫性を維持するため、トランザクション全体を遂行できなくしなくてはならない。また、サービス指向アーキテクチャの出現により、Webベースサービスの特性もあって、トランザクション管理の複雑性はさらに増している。サービスは非同時的で、さまざまな形態を取り、分散し、不透明な場合が多い。サービス指向アプローチの価値を企業がフル活用するためには、資源確保、業務機能調整、並行処理コントロール、そして復旧処理をはじめとするトランザクション管理の仕組みを、サービスの開発者が理解しておく必要がある。

 本稿は、複雑なサービス指向アーキテクチャにトランザクションをインプリメントする際の特性と問題を2回に分けて解説する。今回のパート1では、資源確保、業務機能管理、並行処理コントロール、そして障害復旧をはじめとする複雑な業務活動を整理し、コントロールできるトランザクション・コーディネーションサービス(TCS)を通してトランザクション管理を解説する。一方のパート2では、TCSの候補になるアーキテクチャを紹介する。

J2EE
Common Architectures and Protocols

■ Given an architecture described in terms of network layout, list benefits and
potential weaknesses associated with it.


■ Role of an architect
■ Architecture defined
■ Architectural terms
■ Architecture versus design
■ Fundamentals of architecture
■ Capabilities of an architecture
■ Design goals of architecture
■ Architecture tiers and layers
■ Benefits and weaknesses of architecture
■ Protocols: HTTP, HTTPS, IIOP
Types of Architecture
System Architecture >>>> 60%
Reference Architecture >>>> 50%
Flexible Reference Architecture >>>> 50%

Architectural Design and Principles
Where Architecture Fits in Analysis, Design, and Development >>>> 50%
Architecture vs. Design >>>> first 50%
■ A system architecture document to describe your existing hardware, software, network topology, and other components.
■ An application architecture document to describe the application’s major structure, including a logical view of all architecturally significant components, use case components, and legacy components.
■ A components design guideline to describe all design guidelines and architectural decisions, explain all those decisions, and describe possible consequences if an alternative option is used. These guidelines should capture all-important base determinants that the new component design must respect to maintain the system’s architectural integrity.
■ An architectural prototype to evaluate new technologies, gain experience developing and deploying J2EE applications, build architectural frameworks, and address risks by measuring performance and scalability, as well as proof of concept for the project stakeholders.
Steps in Software Development >>>> 50%
Requirement Analysis/Problem Statement
Object-Oriented Analysis
Architectural Analysis
design guideline(User Case, Sequence, Class, Collaboration Diagrams)
Object-Oriented Design
Architectural Design
Ultimately the object creation
■ Develop package dependency diagrams.
■ Decide how the classes in different package interact.
■ Develop deployment diagrams.
■ Decide where the software components will reside in deployment.

Architectural Terminology >>>> 50%
Abstraction >>>>
Surface Area >>>>
Boundaries >>>>
Brittleness >>>>
Capabilities, Friction, and Layering >>>>

Principles of Architecture
Layering >>>>
Tiers >>>>
Basic Three-Tier Java Technology Architecture >>>>
Capabilities of an Architecture >>>>

Creating an Architecture
Using Distributed Services and J2EE
Enterprise JavaBeans >>>>
Distributed Application Lifecycle >>>>
Iterative Development/MVC >>>>
Simplified Architecture and Development >>>>
Component-Based Application Models >>>>
Support for Client Components >>>>
Support for Business Logic Components >>>>

J2EE API’s and Certification
J2EE Specification >>>>
J2EE Reference Implementation >>>>
Sun BluePrint Design Guidelines for J2EE >>>>

XML and J2EE
Why Use XML? >>>>
Electronic Data Exchange and E-Commerce >>>>
Electronic Data Interchange (EDI) >>>>
Enterprise Application Integration (EAI) >>>>
Software Development and XML >>>>
XML Technology and the Java Platform >>>>

Distributed Programming Services
Naming and Registration >>>>
Remote Method Invocation (RMI) >>>>
Protocols >>>>
Distributed Object Frameworks >>>>

QoSについて 参考資料その1

Java Enterprise System 2005Q4 - Japanese >> Sun Java Enterprise System 2005Q4 配備計画ガイド >> 3. 技術要件
ソリューションライフサイクルの技術要件フェーズでは、使用パターンの分析を行い、ユースケースを特定し、提案する配備ソリューションのサービス品質要件を決定します。

この章で説明する内容は、次のとおりです。
「技術要件について」
「使用パターンの分析」
「ユースケース」
「サービス品質要件」
「サービスレベル要件」

GRASPパターン一覧


Controller

コントローラーパターン。イベント発生時の責務を割り当てる。

Creator

生成者パターン。インスタンス生成の責務を割り当てる。

Expert

情報エキスパートパターン。必要な情報を保持しているクラスに責務を割り当てる。

High Cohesion

高凝縮性パターン。意味的に関係の深い機能を一つのオブジェクトに凝縮させるように責務を割り当てる。

Indirection

間接化パターン。クラス同士を直接結びつけずに、間接クラスを定義する。

Low Coupling

疎結合性パターン。オブジェクト同士の結合度が低くなるように責務を割り当てる。

Polymorphism

多態性パターン。異なる振る舞いを行う同じ操作を定義する。

Pure Fabrication

純粋架空物パターン。人工的なクラスを生成し、責務を割り当てる。

Variation Protected

バリエーション防御パターン。将来予想されるバリエーションの増加を予想しておく。


In pursuit of code quality: Refactoring with code metricsOn-target refactoring with code metrics and the Extract Method pattern

Level: Intermediate

Andrew Glover (aglover@stelligent.com), President, Stelligent Incorporated

30 May 2006

In earlier installments of In pursuit of code quality, you learned how to use code metrics to objectively
measure code quality. This month, Andrew Glover shows you how to use those same metrics and the Extract Method pattern for targeted
refactoring.

In middle school, I had an English teacher who claimed that
"writing is rewriting what one has already rewritten." It
wasn't until college that I actually took his words to
heart. Not surprisingly, once I consciously embraced this practice, I
started to enjoy writing. I started to take pride in
what I was writing. I began to put real effort into how the
words flowed and the meaning I was trying to convey.

When I began my career as a developer, I would read technical books
authored by seasoned professionals and wonder why they spent so much
time writing about code. At the time, coding seemed like such an
easy job -- someone (invariably senior to me) would give me a
problem and I would solve it any way I could.

It wasn't until I started working on large projects with other
developers that I began to understand what taking my craft seriously
meant. It was at this point in my career that I started to consciously
care about the code I was writing, and even to care about the code
others were writing. I now knew that if I didn't pay attention to
code quality, at some point there would
be a late night where I'd be fishing through a mess of spaghetti looking
for the proverbial bad meatball.

My ah ha! moment came in late 1999 when I read Martin Fowler's
seminal book, Refactoring: Improving the Design of Existing Code,
which cataloged a series of refactoring patterns and established, thereby, a
common vocabulary for refactoring. Up until then, I had been refactoring my
code (and even other's code) without knowing it. I now started to take even more
pride in the code I was writing and even in what I was refactoring, for I was
putting real effort into how the code flowed and how it could become
more maintainable over time.



What is refactoring?

In my opinion, refactoring is the act of improving code that has already been improved. In essence, refactoring is a neverending
code-editing process that attempts to enhance the maintainability of a
body of code through structural improvements, without changing
the code's overall behavior. It's important to remember that refactoring
is markedly different from rewriting code.

Rewriting code alters the behavior and even the contract of code,
while refactoring preserves its outward interface. To a client of a
refactored method, there is no perceivable difference. Things work as
they did before, albeit better, most often because of enhanced testability
or an apparent performance improvement.



Subjective and objective refactoring

The question then becomes How do I know when I should
refactor?
The maintainability of a piece of code is arguably a
matter of subjectivity. Most of us would, however, find it far easier to
maintain something we'd written than to maintain someone else's code.
But therein lies the rub -- maintaining your own code throughout your
career is a challenging proposition at best. There are few true "code
cowboys," lucky enough to travel from job to job, never having to
maintain anyone else's code. For most of us, having to maintain someone
else's code is just part of being a programmer. The means of deciding
whether code should be refactored is often subjective.

It's also possible to objectively determine whether code should be refactored, however, whether it's yours or someone else's. In previous articles in this series, I've shown you
how to use code metrics to objectively measure code quality. In fact,
you can use code metrics to easily spot code that might be difficult to
maintain. Once you've objectively determined there's a problem in the
code, you can use a handy refactoring pattern to improve it.




Always run a test case!

The trick to refactoring code you haven't authored is to do so
without making it worse. One thing I learned early in my refactoring
journey was the importance of having a test case before I changed
anything. I learned this lesson the hard way one night as I fished
through my own well-laid-out collection of refactored methods, only to
discover that I'd inadvertently broken someone else's working code by
attempting to refactor it without a corresponding test case. Please heed
my warning and always run a test case before you refactor!




The Extract Method pattern

In the years since Martin Fowler's book was published, many new refactoring
patterns have been cataloged; however, by far the easiest pattern to learn, and arguably still the most effective one, remains Extract Method. In this pattern, a logical portion of a method is
surgically removed and given its own method definition. The body of the
method removed is now replaced with a call to the newly defined method,
as demonstrated in the UML diagram shown in Figure 1:






Figure 1. The Extract Method pattern in action






The Extract Method pattern provides two key benefits:





  • The original method is now shorter and conceivably easier to comprehend.


  • The body of logic removed and placed into its own method is now easier to test.







A cure for cyclomatic complexity


As it turns out, Extract Method is an excellent dose of medicine for
a method that has been infected with a high cyclomatic complexity value.
As you may remember, cyclomatic complexity measures the number of paths
through a method; therefore, it stands to reason that if you
extract some of those paths, the overall complexity of the
refactored method will be less.



For example, imagine that after running a code analysis tool like
PMD,
the resulting report indicates that a class contains a method with a
high cyclomatic complexity value, as shown in
Figure 2:






Figure 2. A cyclomatic complexity value of 23!





Upon a close visual examination of the method, it turns out that
it's unusually long with excessive conditional logic. As I pointed out
earlier in this series (see Resources), this increases
the risk of defects within the method. Thankfully, the updateContent() method is not without test cases.
Even though the method has been deemed risky, the tests mitigate some of the risk.



On the other hand, the tests would have had to be
exceptionally well written to hit each of the 23 paths in the updateContent() method. In fact, a good rule of thumb would
indicate that at least 23 tests should have been written. Moreover,
writing a test case that can precisely isolate the eighteenth conditional in
the method turns out to be extremely challenging!



When small is beautiful


Whether or not to accurately test the 18th conditional in a
long method is a matter of judgment. If that logic embodies true
business value, however, then you'll want to test it, in which case you'll
get to see the Extract Method pattern at work. Minimizing
the risk is a simple matter of breaking up the conditional logic into
smaller pieces, thus creating new methods that can be easily tested.



For instance, the following small piece of conditional logic in the updateContent() method creates a status String. As shown in Listing 1, the logic appears easy enough to isolate:





Listing 1. Conditional logic ripe for the extraction


//...other code above

String retstatus = null;
if ( lastChangedStatus != null && lastChangedStatus.size() > 0 ){
if ( status.getId() == ((IStatus)lastChangedStatus.get(0)).getId() ){
retstatus = "Change in Current status";
}else{
retstatus = "Account Previously Changed in: " +
((IStatus)lastChangedStatus.get(0)).getStatusIdentification();
}
}else{
retstatus = "No Changes Since Creation";
}

//...more code below



By extracting this bit of logic into a succinct, new method (shown in Listing 2) you've achieved two things: one, you've lowered the overall
complexity of the updateContent() method
by about 5; two, you've sufficiently isolated the logic so that you easily test it.





Listing 2. Extract Method yields getStatus


private String getStatus(IStatus status, List lastChangedStatus) {
String retstatus = null;
if ( lastChangedStatus != null && lastChangedStatus.size() > 0 ){
if ( status.getId() == ((IStatus)lastChangedStatus.get(0)).getId() ){
retstatus = "Change in Current status";
}else{
retstatus = "Account Previously Changed in: " +
((IStatus)lastChangedStatus.get(0)).getStatusIdentification();
}
}else{
retstatus = "No Changes Since Creation";
}
return retstatus;
}



Now you can replace a part of the body of the updateContent() method with a call
to the newly created getStatus() method, as
shown in Listing 3:





Listing 3. Calling getStatus


//...other code above

String iStatus = getStatus(status, lastChangedStatus);

//...more code below



Remember to run the existing tests to verify nothing has broken!






Testing private methods


You'll note that the new getStatus() method
defined in Listing 2 is declared as private. This creates an interesting testing challenge should you want to verify the behavior of that method in isolation! There are a number of ways to approach this issue:





  • Make the method public.


  • Make the method protected and put the test case in the same package.


  • Make an inner class in the parent class, which is a test case.




It turns out there is another option as well: leave the method as
declared (that is, private) and use the nifty
JUnit-addons project to test it.



The PrivateAccessor class


The JUnit-addons project has a few handy utilities that facilitate
testing with JUnit. One of the most useful of these is the
PrivateAccessor class, which makes testing
private methods a snap regardless of your
testing framework of choice. The PrivateAccessor
class has no implicit dependency on JUnit, so you can use it with
testing frameworks such as TestNG.



The PrivateAccessor's API is simple -- by
providing the name of the method (as a String) and its corresponding parameter types and
associated values (in Class and Object arrays respectively) to the invoke() method, the value of the invoked method is
returned. Under the covers, the PrivateAccessor class actually turns off object
accessibility using the Java Reflection API. Keep in mind, however, that
if your VM has custom security settings, the utility may not function
correctly.



In Listing 4, I call the getStatus() method
with both parameter values set to null. The invoke() method
returns an Object, hence the cast to a String. Also note that the invoke() method declares that it throws Throwable, so you either must catch it or
let your testing framework handle it, as I've done.





Listing 4. Testing a private method


public void testGetStatus() throws Throwable{
AccountAction action = new AccountAction();

String value = (String)PrivateAccessor.invoke(action,
"getStatus", new Class[]{IStatus.class, List.class},
new Object[]{null, null});

assertEquals("should be No Changes Since Creation",
"No Changes Since Creation", value);
}



Note that the invoke() method is overridden to either take an Object instance,
as in Listing 4, or a Class, in the case that
the desired private method is also static.



Keep in mind also that using reflection to invoke private methods does introduce a level of
brittleness to the resulting tests. Should someone rename the getStatus() method, the above test will fail
miserably; however, if you test frequently, you can quickly make the appropriate fixes.




In conclusion


When battling cyclomatic complexity, keep in mind that the vast
majority of paths coded into an application are inherent to its
overall behavior. That is, it is quite difficult to dramatically reduce
the total number of paths. Refactoring only allows you to push those
paths into smaller sections of code, which then become easier to test.
Those small sections of code also become easier to maintain.



 

Resources

Learn

Get products and technologies
  • JUnit-addons: A useful library for anyone using
    JUnit.

  • PMD: Scans Java code
    for problems.


Discuss
 

About the author

Andrew Glover is the President of Stelligent Incorporated, which helps companies address software quality with effective developer testing strategies and continuous integration techniques that enable teams to monitor code quality early and often. He is the co-author of Java Testing Patterns (Wiley, September 2004).


テーマ : ソフトウェア - ジャンル : コンピュータ

| ホーム |


 BLOG TOP  » NEXT PAGE