I run a consulting and training company that helps organizations build better software faster.
We provide a variety of services including:
Next week is going to be a busy week:
I hope to see you there!
I recently added some new goals to the Cloud Tools Maven plugin that expand its capabilities:
You can also specify the structure of the cluster when using cloudtools:deploy:
At the East Bay/Oakland Java SIG on Wednesday night (4/16), Dan Pritchett and Randy Shoup will be talking about the eBay architecture.
System designers constantly struggle with how to build a feature that fulfills product requirements, while keeping the system fluid and maintainable. As product requirements get more and more complicated, tighter integration with existing data and product features becomes increasingly important to keep the negative impact to the user experience at a minimum. If the page or program loads more slowly, while giving the user the rich experience - have we succeeded or failed?
In this session, eBay's Dan Pritchett and Randy Shoup will delve into the strategies and driving principles that guide eBay's development teams across the world. They will talk about real world examples of how these principles will allow you to design what, until now, has been thought to be impossible - scalable, high performance and agile systems that do not get in the way of the organization's feature velocity. The guiding principles, methodology, and patterns are what have allowed eBay to scale a large development organization across four continents.
Attendees will learn:
This session will cover the key enabling design patterns, methodologies, and best practices that allow us to maximize these factors and produce a highly scalable eCommerce platform that is used by millions of people each day. The following questions will be answered:
The meeting starts at 6.30pm in downtown Oakland.
Reed Smith Law firm
1999 Harrison St
24th Floor
Oakland, CA 94612-3572
See the directions and don't forget to register in order to ensure that we order enough pizza (and to keep building security happy).
The Java SIG meets on the 3rd wednesday of the month and we primarily talk about enterprise Java related topics. In May, Bill Venners (http://www.artima.com/) will be talking about the Scala language and in June Tom Hill will be talking about Lucene and Solr.
I hope to see you there..
Cloud Tools now includes a plugin for deploying Grails applications to Amazon's Elastic Compute Cloud (EC2). Like the Cloud tools Maven plugin, this plugin makes deploying a web application to EC2 extremely easy. It currently provides the following Grails scripts:
I plan to release it in the next few days but in the meantime please contact me if you would like to try it out.
Over the past year I've given a few presentations on how to clean up those bloated service classes that are sadly all to common in Java EE applications. A real-world example of this kind of service would be too large to include in a blog so here is an example that is only a minor mess:
public class AccountServiceProceduralImpl implements AccountService {
private Log logger = LogFactory.getLog(getClass());
private final AccountDao accountDao;
private final BankingTransactionDao bankingTransactionDao;
public AccountServiceProceduralImpl() {
this.accountDao = new JdbcAccountDao();
this.bankingTransactionDao = new JdbcBankingTransactionDao();
}
public BankingTransaction transfer(String fromAccountId, String toAccountId,
double amount) {
BankingSecurityManager.verifyCallerAuthorized(AccountService.class,
"transfer");
logger.debug("Entering AccountServiceProceduralImpl.transfer()");
TransactionManager.getInstance().begin();
AuditingManager.getInstance().audit(AccountService.class, "transfer",
new Object[] { fromAccountId, toAccountId, amount });
try {
Account fromAccount = accountDao.findAccount(fromAccountId);
Account toAccount = accountDao.findAccount(toAccountId);
double newBalance = fromAccount.getBalance() - amount;
switch (fromAccount.getOverdraftPolicy()) {case Account.NEVER:
if (newBalance < 0)
throw new MoneyTransferException("Insufficient funds");break;
case Account.ALLOWED:
Calendar then = Calendar.getInstance();
then.setTime(fromAccount.getDateOpened());
Calendar now = Calendar.getInstance();
double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR);
int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH);
if (monthsOpened < 0) {yearsOpened--;
monthsOpened += 12;
}
yearsOpened = yearsOpened + (monthsOpened / 12.0);
if (yearsOpened < fromAccount.getRequiredYearsOpen()
|| newBalance < fromAccount.getLimit())
throw new MoneyTransferException("Limit exceeded");break;
default:
throw new MoneyTransferException("Unknown overdraft type: "+ fromAccount.getOverdraftPolicy());
}
fromAccount.setBalance(newBalance);
toAccount.setBalance(toAccount.getBalance() + amount);
accountDao.saveAccount(fromAccount);
accountDao.saveAccount(toAccount);
TransferTransaction txn = new TransferTransaction(fromAccount, toAccount,
amount, new Date());
bankingTransactionDao.addTransaction(txn);
TransactionManager.getInstance().commit();
logger.debug("Leaving AccountServiceProceduralImpl.transfer()");
return txn;
} catch (MoneyTransferException e) {logger.debug(
"Exception thrown in AccountServiceProceduralImpl.transfer()", e);
TransactionManager.getInstance().commit();
throw e;
} catch (RuntimeException e) {logger.debug(
"Exception thrown in AccountServiceProceduralImpl.transfer()", e);
throw e;
} finally {TransactionManager.getInstance().rollbackIfNecessary();
}
}
public void create(Account account) {
BankingSecurityManager.verifyCallerAuthorized(AccountService.class,
"create");
logger.debug("Entering AccountServiceProceduralImpl.create()");
TransactionManager.getInstance().begin();
AuditingManager.getInstance().audit(AccountService.class, "create",
new Object[] { account.getAccountId() });
try {
accountDao.addAccount(account);
TransactionManager.getInstance().commit();
logger.debug("Leaving AccountServiceProceduralImpl.create()");
} catch (RuntimeException e) { logger.debug("Exception thrown in AccountServiceProceduralImpl.create()",e);
throw e;
} finally {TransactionManager.getInstance().rollbackIfNecessary();
}
}
}
This code has a few characteristics that make it difficult to maintain and test:
Compare and contrast this with a service from version of the same code that uses aspects, dependency injection and a real domain model:
public class AccountServiceImpl implements AccountService {
private final AccountRepository accountRepository;
private final BankingTransactionRepository bankingTransactionRepository;
public MoneyTransferServiceImpl(AccountRepository accountRepository,
BankingTransactionRepository bankingTransactionRepository) {this.accountRepository = accountRepository;
this.bankingTransactionRepository = bankingTransactionRepository;
}
public BankingTransaction transfer(String fromAccountId,
String toAccountId, double amount) throws MoneyTransferException {Account fromAccount = accountRepository.findAccount(fromAccountId);
Account toAccount = accountRepository.findAccount(toAccountId);
fromAccount.debit(amount);
toAccount.credit(amount);
TransferTransaction txn = new TransferTransaction(fromAccount,
toAccount, amount, new Date());
bankingTransactionRepository.addTransaction(txn);
return txn;
}
public void create(Account account) {accountRepository.addAccount(account);
}
}
As you can see there are some significant improvements:
To find out more take a look at these presentations:

