Crafting a Spring SOAP web service project | domain model, high-level layers of architecture

Starting a web service from scratch can be daunting. But no worries, I’ve experienced exactly the same fear as you are right now! In this tutorial, I will briefly go over coding up a SOAP web service from scratch, adopting Spring Framework.

Even though this is not the first tutorial for the spring SOAP web service, a lot of existing tutorials do not leverage the latest API of spring framework, e.g. populate WSDL file without defining web.xml (deployment descriptor), auto-wiring of all the bean instances and Application configurations, how to drive from idea to implementation etc.

Define the domain models

Suppose our employer asked us to build up a backend system that supports a web page to store person’s information into an address book and retrieve from it. How should we start?

I would start with designing the domain models. This is the first step to concretize the backend system design.

Below is one way to model the domain classes:

Screen Shot 2015-08-18 at 6.26.59 PM

Contract-first design

First thing first, define the contract of your web service application, i.e. the API you would like to expose to your client. A good design originates from the top-down approach. By exposing the API to the client, you will be able to realize the dataflow from your application’s endpoint to its internal. Remember your client is your god.

For example, in my web service project named Address Book, I first created a web service configuration. It auto populates the WSDL file, and the client should be able to tell how to consume the SOAP API. Below is the example of part of the WSDL file the Address Book application generated:


In this wsdl file, I defined eight web service operations:

  • OpenAccount – Open up an account when the user sign up with the username and password. After signing up, the address book is automatically populated for the user
  • CloseAccount – Deactivate the user account
  • AddPerson – Add person into the address book
  • FindPerson – Find the person in the address book
  • AddAddress – Add the address for the person in the address book
  • AddEmail – Add the email for the person in the address book
  • AddPhoneNumber – Add the phone number for the person in the address book
  • FindAccount(for the internal system) – Find the account by the username

Filling up the Address Book

Suppose we want to sign up for a free address book account as a user. We would supply the username and password. The front-end web page would send the SOAP request – which contains the username and password in the body part – to the web service, and (hopefully) the web service would respond a success, like below:

Screen Shot 2015-08-19 at 6.12.44 PM


Meanwhile in the database backend, we should see the username and password stored (apparently the password should not be stored in a plain text in reality):

Screen Shot 2015-08-19 at 6.11.14 PM


Suppose now we want to add some person into the address book so we supply some basic information for the person on the web page. Again, the front-end system would send SOAP request to the backend:

Screen Shot 2015-08-19 at 6.54.08 PM

Meanwhile the database would store the person’s basic information.

Screen Shot 2015-08-19 at 6.54.01 PM

Suppose now we want to add some more information to this person, like the phone number:

The SOAP call will be like below:

Screen Shot 2015-08-19 at 7.01.17 PM

And we see the database stores the phone number:

Screen Shot 2015-08-19 at 7.00.35 PM

Finally if we want to deactivate the account:

The SOAP call will be like below:

Screen Shot 2015-08-19 at 7.05.00 PM

And there’s a subtle change in the existing entry for the user jsy1218:

Screen Shot 2015-08-19 at 7.05.17 PM

Now you will notice the account_status has been changed from OPEN to CLOSED, a.k.a the account gets soft deleted. (Soft delete is a common pattern used in enterprise application. The idea here is to preserve th entries so as for text mining. Well reserved data could be used for business intelligence.)

Convention Over Configuration Application setup (web.xml free!)

The first step for the SOAP web service is to setup the servlet and define the WSDL. Traditionally, we would do these in the web.xml, however, there is a Java-based configuration, since Spring 3.0:


public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();



return new ServletRegistrationBean(servlet, "/addressbook/*");


First we set up the MessageDispatcherServlet. Don’t forget to set the application context and transform wsdl locations to true. Then, when we return the ServletRegistrationBean instance, we can set the servlet url matching pattern to accept the SOAP request.

 	@Bean(name = "addressbook")
	public DefaultWsdl11Definition defaultWsdl11Definition() throws IOException {
		    DefaultWsdl11Definition wsdl11Definition = new       DefaultWsdl11Definition();

    Resource[] xsdResource = {
                new ClassPathResource("com/sijiang/webservice/soap/message_format/OpenAccountRequest.xsd")  ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/CloseAccountRequest.xsd") ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/AddPersonRequest.xsd") ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/FindPersonRequest.xsd") ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/AddAddressRequest.xsd") ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/AddEmailRequest.xsd") ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/AddPhoneNumberRequest.xsd") ,
                new ClassPathResource("com/sijiang/webservice/soap/message_format/FindAccountRequest.xsd")
    		CommonsXsdSchemaCollection schemaCollection = new    CommonsXsdSchemaCollection(xsdResource);
    		return wsdl11Definition;

One takeaway is to notice you have to give the bean name for DefaultWsdl11Definition instance. This is to tell DefaultWsdl11Definition the name of the WSDL file to be auto-generated. Another one is don’t forget to call
schemaCollection.afterPropertiesSet() otherwise all the XSD schema won’t be set for the WSDL file.

Together this java-based configuration could replace the traditional web.xml deployment descriptor.

Configure Service Endpoint

Now we have the non-traditional deployment descriptor, we need to let the service know how to handle the requests. One way is to annotate the method with PayloadRoot as the handler for incoming requests.

	@PayloadRoot(namespace = ADD_PERSON_NAMESPACE_URI, localPart = "AddPersonRequest") 
	public AddPersonResponse addPerson(@RequestPayload AddPersonRequest request) {
		    int age = request.getAge();
    		String firstName = request.getFirstname();
		    String lastName = request.getLastname();
		    String username = request.getUsername();
    		String result = "success";
    		try {
        			addressBookManager.addPerson(age, firstName, lastName,     username);
		    } catch (Exception e) {
        			result = "failure";
        			LOGGER.error("Error when adding person to the account. ", e);
    		AddPersonResponse response = new AddPersonResponse();
    		return response;

Notice @RequestPayload and @ResponsePayload marshall/unmarshall the bytes stream into the AddPersonRequest and AddPersonRequest, which are generated by the JAXB library.

Externalized Dependency Injection and Application Configuration

Before Spring 2.5, whenever one writes a Spring web service, one has to declare the application context within the xml configuration file. With the growth of the application, the number/amount of xml configuration will also grow in proportion.

With the bless of spring annotation, we can even externalize the application context into the POJO! For example, below is the app config for the address book project:

package com.sijiang.addressbook.app_config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

public class AddressBookAppConfig {

and, for example, the repository bean is annotated in the AddressBookRepositoryImpl class. This repository bean will be the candidate for the dependency injection for the application:

package com.sijiang.addressbook.repo.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.sijiang.addressbook.dao.AccountDAO;
import com.sijiang.addressbook.dao.AddressBookDAO;
import com.sijiang.addressbook.dao.PersonDAO;
import com.sijiang.addressbook.model.Account;
import com.sijiang.addressbook.model.Address;
import com.sijiang.addressbook.model.AddressBook;
import com.sijiang.addressbook.model.Email;
import com.sijiang.addressbook.model.Person;
import com.sijiang.addressbook.model.PhoneNumber;
import com.sijiang.addressbook.repo.AddressBookRepository;

public class AddressBookRepositoryImpl implements AddressBookRepository {
	private AddressBookDAO addressBookDAO;
	private PersonDAO personDAO;
	private AccountDAO accountDAO;
	public void setAddressBookDAO(AddressBookDAO addressBookDAO) {
		this.addressBookDAO = addressBookDAO;
	public void setPersonDAO(PersonDAO personDAO) {
		this.personDAO = personDAO;

	public void setAccountDAO(AccountDAO accountDAO) {
		this.accountDAO = accountDAO;

	public void closeAccount(Account closingAccount) {

	public void openAccount(Account newAccount) {

	public Account findAccountByUsername(String username) {
		return this.accountDAO.findAccountByUsername(username);
	public AddressBook findByAddressBookId(int addressBookId) {
		AddressBook addressBook = this.addressBookDAO.findByAddressBookId(addressBookId);
	    for (Person person : addressBook.getPersons()) {
	    		person = findByPersonId(person.getPersonId());
	    return addressBook;

	public Person findByPersonId(int personId) {
		return this.personDAO.findByPersonId(personId);
	public List findPersonsByLastnameAndFirstname(String firstName,
			String lastName) {
		return this.personDAO.
				findPersonsByLastnameAndFirstname(firstName, lastName);

	public void addPersonIntoExistingAccount(Person defaultPerson, String username) {
		this.personDAO.addPersonIntoExistingAccount(defaultPerson, username);

	public void addEmailToPerson(Email defaultEmail, String firstName,
			String lastName) {
		this.personDAO.addEmailToPerson(defaultEmail, firstName, lastName);

	public void addPhoneNumberToPerson(PhoneNumber defaultPhoneNumber, String firstName,
			String lastName) {
		this.personDAO.addPhoneNumberToPerson(defaultPhoneNumber, firstName, lastName);
	public void addAddressToPerson(Address defaultAddress, String firstName,
			String lastName) {
		this.personDAO.addAddressToPerson(defaultAddress, firstName, lastName);

The AddressBookAppConfig class doesn’t have to contain any code block. On the service startup time, it will scans through the declared package directories: “com.sijiang.addressbook.service_config”, “com.sijiang.addressbook.webservice_config”, and “com.sijiang.addressbook.repository_config”. As long as it finds the bean instances on the startup time, Spring is able to inject the dependencies.

One side benefit of following annotation way is it powerfully packs the metadata in a concise way, yet not losing any important information, just like the xml configuration.

Database Interaction

In rare case, the enterprise-level application doesn’t need to persist the data into the backend database, unless the application only involves the stateless dataflow. Spring framework provides a rich way to interact with different types of database. The address book project adopts JdbcTemplate API to abstract out the database connection and interaction and MySQL as the data storage engine. Here we won’t cover how to set up the local instance of MySQL. Please check MySQL manual guide for reference:

First in the JDBCDriverConfig class, we instantiate the bean instance for JdbcTemplate and then set the DataSource to tell the application how to connect database server.

package com.sijiang.addressbook.repository_config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import com.sijiang.addressbook.repo.AddressBookRepository;
import com.sijiang.addressbook.repo.impl.AddressBookRepositoryImpl;

@ComponentScan({ "com.sijiang.addressbook.repo.impl",
		"com.sijiang.addressbook.dao.impl" })
@EnableTransactionManagement(proxyTargetClass = true)
public class JDBCDriverConfig implements TransactionManagementConfigurer {
	private static final JdbcTemplate jdbcTemplate = new JdbcTemplate();
	private static final DriverManagerDataSource dataSource = new DriverManagerDataSource();

	private String driverClassName;
	private String url;
	private String username;
	private String password;
	@Bean(name = "JDBCTemplate")
	public JdbcTemplate getJdbcTemplate() {


		return jdbcTemplate;
	public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
	    return new PropertySourcesPlaceholderConfigurer();
    public PlatformTransactionManager txManager() {
        return new DataSourceTransactionManager(dataSource);

    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return txManager();

Also notice how you can abstract out the database connection information from the source code. In the JDBCDriverConfig class, database connection information, driver class name, url, username and password are injected from the property file named “”. This value injection technique will always work as long as file is on the project’s class path.

Then on the application side, we prepare the SQL statements for the database operation:

package com.sijiang.addressbook.dao.impl;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import javax.annotation.Resource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;

import com.sijiang.addressbook.dao.AccountDAO;
import com.sijiang.addressbook.model.Account;
import com.sijiang.addressbook.model.Account.AccountStatus;

public class JDBCAccountDAOImpl implements AccountDAO {
	private static final String OPEN_ACCOUNT = "INSERT INTO account (username, password, account_status) "
			+ " VALUES (?, ?, ?) ";

	private static final String CLOSE_ACCOUNT = "UPDATE account "
			+ " SET account_status = ? " + " WHERE username = ? ";

	private static final String FIND_ACCOUNT_BY_USERNAME = "SELECT username, password, "
			+ " create_date, last_login_time, account_status "
			+ " FROM account " + " WHERE username = ? ";

	private JdbcTemplate JDBCTemplate;

	@Resource(name = "JDBCTemplate")
	public final void setJDBCTemplate(JdbcTemplate JDBCTemplate) {
		this.JDBCTemplate = JDBCTemplate;

	public void openAccount(Account newAccount) {
				new OpenAccountPreparedStatementSetter(
						newAccount.getUserName(), newAccount.getPassWord(),

	public void closeAccount(Account closingAccount) {
				new CloseAccountPreparedStatementSetter(
				, closingAccount.getUserName()));


	public Account findAccountByUsername(String username) {
		Account searchedAccount = JDBCTemplate.queryForObject(
				FIND_ACCOUNT_BY_USERNAME, new Object[] { username },
				new int[] { Types.VARCHAR },
				new FindAccountByUsernameRowMapper());

		return searchedAccount;

	private class FindAccountByUsernameRowMapper implements RowMapper {

		public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
			String username = rs.getString("username");
			String password = rs.getString("password");
			Date createDate = rs.getDate("create_date");
			Date lastLoginDate = rs.getDate("last_login_time");
			AccountStatus accountStatus = AccountStatus.valueOf(
					AccountStatus.class, rs.getString("account_status"));

			Account searchedAccountByUsername = new Account.AccountBuilder(
					username, password, accountStatus).CreateDate(createDate)

			return searchedAccountByUsername;

	private class OpenAccountPreparedStatementSetter implements
			PreparedStatementSetter {
		private final String userName;
		private final String passWord;
		private final AccountStatus accountStatus;

		private OpenAccountPreparedStatementSetter() {
			throw new UnsupportedOperationException();

		public OpenAccountPreparedStatementSetter(final String username,
				final String password, final AccountStatus accountStatus) {
			this.userName = username;
			this.passWord = password;
			this.accountStatus = accountStatus;

		public void setValues(PreparedStatement ps) throws SQLException {
			ps.setString(1, userName);
			ps.setString(2, passWord);
			ps.setString(3, accountStatus.toString());

	private class CloseAccountPreparedStatementSetter implements
			PreparedStatementSetter {
		private final String accountStatusAsString;
		private final String userName;

		private CloseAccountPreparedStatementSetter() {
			throw new UnsupportedOperationException();

		public CloseAccountPreparedStatementSetter(final String accountStatusAsString,
				final String userName) {
			this.accountStatusAsString = accountStatusAsString;
			this.userName = userName;

		public void setValues(PreparedStatement ps) throws SQLException {
			ps.setString(1, this.accountStatusAsString);
			ps.setString(2, this.userName);

Notice how the input parameter addressBookId in the JDBCAddresBookDAOImpl class gets passed down from the upstream call and then replace the question mark in the SQL statement on the runtime. This is a powerful feature that JdbcTemplate API provides – populate the input and/or output parameters on the runtime so that your database operation can be parametrized based on the use case.

Also, notice in the inner class FindAddressBookRowMapper, how it maps the fields from database to application. One gotcha is the column names ResultSet bases off has to match the ones in the SELECT clause of the SQL statement that is passed along to the JdbcTemplate. In this case, take a closer look at the SQL statement in the JDBCAddresBookDAOImpl class, especially the SELECT clause.

Check out the Source Code

Check out the source code at:

Follow the README for the setup and version requirement.


  1. a good amount of details about the java-based web service config)
  2. (a detailed coverage of getting rid of web.xml)
  3. between different annotations for dependency injection)
  4. (Simpler example regarding the java-based application config.)
  5. SOA in Practice, The Art of Distributed System Design By Nicolai M. Josuttis (some of the concepts in this post are from SOA, e.g. dependency injection and convention over configuration. It talks about the design paradigm of the distributed system on the higher level)

Ramping up on the Enterprise-level Application by Example | domain model, high-level layers of architecture

Last time, I talked about how to ramp up on the enterprise-level application the first time you face it. By the end of the last post, I promised that I would give an example to illustrate the high-level points aforementioned in my last post.

Suppose that we would like to automate the process of ordering the food at a food truck(I’m foodie by the way). We think a single web service should be able to do this job. We would like to name this web service “Food Truck? Mouth Watering…” (Apparently It’s not an appropriate name in a formal context though)

Below is the domain model in my mind:

Class Diagram for Food Truck Menu
Class Diagram for Food Truck Menu

Below is one way to lay out high-level layers of architecture of “Food Truck? Mouth Watering…”:

High-level Layers of "Food Truck? Mouth Watering..."
High-level Layers of “Food Truck? Mouth Watering…”

You may already realize that when you transform diagrammatical expression into the programming language, it will become less intuitive. Thinking backwards, how effective you would be if you dive straight into the ocean of code without a rough idea of which layer is of your interests?

As requested by a friend of mine, in my next post (or maybe a series depending on the scope), I would talk about how I planned out my week ahead of time and how I rolled out my plan. The intended audience would get expanded. My original intent would be focusing on summarizing my own mistakes for those inexperienced, but since I see a great need of help from him, I would like to share my experience on how to get a hold of my time.


Due to long week, I would like to work a little bit on the visualization of my blog. But complete customization would require some development effort, so I may just pick up some existing themes and modify from there for now.

The first time you face the source code for an enterprise-level application

I can still remember how overwhelmed I was when checked out the source code for our application; it was way too many lines of code! I didn’t know how to get familiar with the system or how I could contribute to the system. It appears to be a black box to me.

Now when I think back about that moment and how I could pick up on our own system quicker and more effective, I think the following things are important: the role/purpose of the application, the domain model of the application, and high-level layers of architecture.

  • The role/purpose of the application

The first thing is you need to know is what’s the role of your application? It exists to serve some client’s need, and you need  to figure what’s this need. It defines why your system exists.

  • The domain model of the application

Unless your system involves zero dataflow, otherwise it has to have a pre-defined domain model to wrap up the data. Now thinking back I was daunted by the amount of data we transfer to our upstream/downstream systems, I wasn’t able to identify which are core data and which aren’t. If I could tell which set of data creates an instance of encapsulated domain model, I would feel less daunted.

  • high-level layers of architecture

I personally think this is the most important thing to ramp up on a system, especially if you want to contribute new code to the existing code base. Before I had a big picture of our system’s high-level layers, I usually looked into the code with minimal clue, just like searching for a needle in a haystack. Now when I need to look into the code, I would like to think about which layer of the system most likely sits the answers I’m looking for.

Some of my friends argue by saying understanding use case of the system is also important. I would say you are not wrong, but understanding the use case has to come with time, unlike the above three aspects of the system which you could ramp up on.

I thought I would be diligent enough to put an example here, but I’m not 🙂 In my next post, I will make up an example of my own to illustrate my aforementioned points.

Any complaints or grievances?

Let’s spell “Debugging” by a real-world example!

Remember we did a pop quiz last time – how do you debug? Here’s the answer laid out in the book “Debugging” (David Agans):

  • Understand the system
  • Make it fail
  • Quit thinking and look
  • Divide and Conquer
  • Change one thing at a time
  • Keep an audit trail
  • Check the plug
  • Get a fresh view
  • If you didn’t fix it, it ain’t fixed

How about this? Let me give an real-world example and you try to identify which rules did the people in story follow/violate?

One day morning, our team learned that our system didn’t capture a considerable amount of money due to some external and internal reasons. Plus, according to the past experience, if we couldn’t capture the money by the end of next day, then the odds are we may likely lose the money… (~9a.m.)

The senior engineer in our team quickly spotted down a bug in our system that causes these miscapturing of the money. Then the team started to discuss about potential strategies to get back the money. In this case, hot fix and emergency deployment was not a viable option due to some reason. After looking into the persisted states for these miscaptured transactions, we decided to adopt a two-way strategy: alter the persisted state to when the transaction was about to going through in the database, and then manually fire up the client call to transaction capture API to secure the money. (~11a.m.)

We had two ways to alter the persisted state in the database, and one way seems to involve less time than the other because it doesn’t have to go through the process. We started working on this way, only to realize this approach doesn’t work. It’s not working because we didn’t have the sufficient permission. We could’ve realized this earlier by running some existing code that requires the same level of permission. We called it the end of day. (~7p.m.)

Next day the team agreed to go with the other approach. We ended up encountering another unexpected odds. One simple SQL statement resulted in a long hanging operation. Our senior database developer were able to explain the long latency, but he wasn’t able to give a solution to it, because the database server seems to do some additional background jobs even though we didn’t ask to and it’s impossible to inhibit them at the client level. Again the team were stuck. (~1p.m.)

Our boss asked senior database developer if it’s possible to use another SQL statement. The team spent some time in figuring out how and we did find another way that’s worth trying. This time it works! We managed to solve this production issue right before it falls off.(~3p.m. phew…)

I don’t think all the debugging rules applies in this story, but try to spot down some rules we followed or violated 🙂

When you can use search engine to get (almost) all the answers…

Sorry for the long delay in posting my second blog… I’ve been a little busy lately and I’m trying to host my own domain and put all the stuff under my website. Before I jump into the topic, I would like to make a minor change of the claim in my last post. In my last post, I said every developer should keep reading and comprehending new technical books. After a little thought on this, I think my claim was too categorical. So I would like to rephrase to make it sound like “every developer should have some reading habit for the technical books, but you determine the pace and frequency of reading new books”.

When I talk to my peers about why I think reading technical books are important,sometimes I got different opinions. Some people think since 99% percent of the time we can find the answers by searching the answers online, why bother reading the book? Plus, we are the engineers, we should quickly jump into problem solving. Only when we got stuck and out of strategy, then we ask for help. This is a classical engineering approach.

Well, I personally think there are a couple of benefits you can gain only by reading the books, mainly:

  1. Raise the awareness. For example, If someone asks you how you debug your code, how would you answer? Before I read the book “Debugging”, I thought debugging was no more than effectively use the debugging tool in IDE. But this book completely revamped my view of how to debug my code. Now I realize every time I spend too much on debugging is because I’m not following rules covered in this book.
  2. Better pointer to the reference. If you don’t read the technical books and every time you got stuck on some problems, you have to search online for the answer. But are these answers correct and reliable 100% of the time? Or, those reference books may be more trustworthy? Plus, do not expect you can always find the answers just by searching online, because sometimes you don’t even know how to phrase the problem. By reading the books, you may have a better awareness of the problem (which goes back to the first point) and realize how to possibly get the answers.
  3. Better use of words and phrases in the technical context. With the large volume of words and phrases only applicable in the technical context, you won’t get enough education of absorbing them by just writing the code and searching answers online. By reading those books, you will slowly get exposed to those buzzwords that only newbie developers don’t know. One of my examples I have to roughly explain to my friend(who is also a web service developer) what is “load balancer”.

One more added benefit that is top off my head is that these technical books have overlaps of some concepts. By reading more books, you will also get a rough idea of what concepts are important and what are not.

In my next post, I will give a concrete example of how I waste my time in debugging when I violate the rules covered in “Debugging”.

Let’s wrap it up by a pop quiz: how do you debug you code?

Why I start to write blogs?

(Migrated from my blog site)

My Chinese name is Siyu Jiang and I work for Expedia as a software developer. For those who don’t speak mandarin, you can call me See-You-John 🙂

I consider myself an introvert, either in the form of traditional face-to-face communication or on any “funky” social networking app. So why all of the sudden I start to break out of my own silence? Couple reasons: 1. As a fresh out of college, my work and social life has been very different than the school counterpart. I feel the need to share my experience on how I adjust the life style changes. 2. I’ve learned a lot from my workplace and I wish I could share some minor insights to those who are interested in the entry-level software field. 3. I want to put my thoughts and mind into a complete and sharable form.

In my next blog, I will briefly talk about why everyone developer should keep reading and comprehending new technical books. Just a heads-up, I’ve read:

“Test-Driven Development” by Kent Beck
“Debugging” by David Agans
“Effective Java” by Josh Blotch (must-read for java developer)
“Release it” by Michal Nygard
“SOA in practice” by Arnon Rotem-Gal-Oz
“Soft Skills: The software developer’s life manual” by John Sonmez (in-progress)

I’m not saying that I completely buy the concepts and insights from these books, but everytime I worked on sth. and revisited the relevant part of the book, I have those “gotcha!” feelings.

I intentionally made my first blog short so that I won’t steal too much of your time 🙂 (don’t tell me it’s too much read for you…)