8 hours iPhone Development and my head spins. This is quite a long time since that happened to me the last time. I knew that it wouldn't be easy to delve into a new language (Object-C), framework (Cocoa) and a new development environment (XCode) but it was harder than I expected. This is not the first development framework of its kind that I use (PowerBuilder, Oracle Forms) but it takes some time to get use to know which buttons to turn in order to get the desired results.
That said it is exhilarating to feel challenged again on a higher level that fiddling around in the low level Hibernate or Spring swamp. Still it will take some time and I will be stumped quite often in the next few weeks. Eventually I hope I am ready for iPhone 3.0 when it finally comes out.
Cheers - Andy
In my current project there were some tests failing on and off. We were getting used to that fact and just ignored even though our continuous integration build didn't like it that much.
In general I hate such situation and I would have looked into that but unfortunately I did not find time to do so. Well, now as the project comes to an end for me I finally stumbled over the culprit just by chance. It turned out that the error came from overly complicated code and compared with some Java shortcomings were responsible for the error.
The author or that particular method had the task to compare two date objects if they are of the same day (disregarding fractions of a day). In Oracle that is call truncating a date. There he implemented a truncateDate method taking a date as argument:
Now in Java that can fail because the Date object's time may vary even when created with the same time in milliseconds. This means that this might be true or might be false:
long ts = 1234567890;
new Date( ts ).getTime() == new Date( ts ).getTime()
Isn't that funny. I discovered that when trying to convert Dates back and forth over JSon. This also means that the a comparison of the two truncated dates with the method above might or might not return the same long value. To fix it I retired the truncateDate method and created a compareTruncatedDate method which compares the dates using theirs Year, Month and Day of Year value. Now the tests are returning the same results over and over again.
Have fun - Andy
Lately I see a lot of talk about Code Coverage even at some places where managers just want to get the job done however messy it is. Personally I think that Code Coverage like many other alike tools (style guidelines, code metrics etc) are only Manager's Gimmicks allowing them to put a check mark on an item and if checked they can feel good about them.
Let's face it developing Software is a complex, difficult and time consuming endeavor that needs excellent developers to make it work. And because of that many Managers feel to be out of control and so they want to be more in control by measuring the software because they are not able to evaluate the code by themselves and they don't want to rely on their staff.
Unfortunately tools are not able to understand an entire project and so their measurement is a close up view rather than a birds eye view. Even I don't know how good code is until I evaluated pieces of it or ran into severe problems. That does not mean that I don't have a gut feeling pretty early on about it and so far that feeling was quite often right on the money. When I design and write code I don't know if that code is good or not because there are so many inside and outside factors which I can't control. That said I follow my personal principles, I am not afraid to ripe code apart to clean it up and will write some test cases. My design and code is in my view validated when requests for changes can be implemented easily and without a lot of side effects.
Now my personal principles are (in no particular order):
Let me elaborate a little bit on these items. The layering is important to make sure that we humans can manage code and can rearrange code if necessary. For example in a project developers added DAO classes inside the Entities in order to create rich domain models. I don't mind the rich domain model but I don't like to have them inside an Entity which purposes is to map to a DB table record. This makes it impossible to extract the Entities into their own modules because they are going to be used in multiple modules. This also makes the code more complicated because a method call to an Entity can lead to a slur of other DAO and Entities calls and maybe even more calls because DAO may call other classes as well. Finally it also makes it difficult to deal with multiple Entities on the same table to deal with the amount of data retrieved.
KISS means that developers should not outsmart themselves and others. When code gets to complicated it is time to refactor and to make sure that method represent a particular task. For example I had to deal with a method that used dynamic HQL generation in order to search for certain records which is called by many different places in the code. A slight change made it necessary to test half of the application. That piece was soft badly written that it even contained dead code.
Refactoring should be a constant task of every developer. If code grows it becomes more and more difficult to do so it should be tackled right away.
Enclosing data in meaningful object makes it possible to keep changes localized rather than have to change many method signatures and algorithms. For example I created a criteria object for entity searches. Any change in the how searches where done was localized to where the object was created and when it was used. If I would have used Query by Example then I would have to change many classes and method signatures.
Well, a big part of my daily tasks is to look at other people's code and try to understand and then fix it. Inside that code I see fairly easily the history on how the code came about and why it ended up this way. More often than not developers who had to fix a bug or enhance it just made what they were asked to making the code a little bit uglier in the process. When I have to fix a problem is use the invested time to refactor and simplify the code in the process so that I and other can profit in the future. Quite often a bug is merely a symptom rather than the actual cause and fixing just the bug will not elevate the underlying cause.
Unit tests are great if they cover a lot of code. Therefore they should perform a high level task rather than just testing a single method. Any developer which needs a unit test for a simple method should look for another job. This will also increase the chance to catch a regression bug because it tests also the interaction of various methods and classes.
Finally my most dearest point which leads to a lot of heated discussion and dismissals but over and over I am vindicated in the long haul. Laziness is great but only if done with respect on the long haul. Short term gain have to be paid in the long haul, always. For example the Query by Example mentioned above is nice but it will cause troubles and should not be used in production code. An Entity just contains the attributes and so it cannot cover stuff like search parts of a string, between values, search values outside the entity and so on. But even if you can make it work it is hard to read because the method signature is not expressive. For example MyEntity do( MyEntity entity ) is not the same as MyEntity search( MyEntityCriteria criteria ). No we could change the naming but if the code has to be decompiled that info is gone. Another thing is Spring's Autowired annotation. There are several things that I don't like. First it makes testing uglier because the linking is already done and the only way to fix it is to write your own test spring configuration which may lead to problems if that one is not keep in sync with the regular one. In addition it does not show the dependencies in the spring configuration file leading to many runtime failures because of missing or duplicate dependencies.
I am pretty sure that I follow more principles but these are the one that pop up in my head first and are the ones that lead to the most problems. In any case quality is not achieve easily and Manager should invest in their developers rather than tools and processes.
Don't forget: Great Software is developer by a handful of Great Developers
-Andy
In order to revamp our company's website we need to redo some of the graphic art and so I went out to search for a good vector and pixel graphic editor. The only good vector graphic editor I found beside the overpriced Adobe tool was Inkscape which does the trick but it runs inside X11 which is not really user friendly but I am not going to pay over $600 for a program that is rarely use. Now, for the pixel graphic editor there are more choices available and I ended up having a look at Pixelmator and GIMP.
At the first glance there is raw power (GIMP) against a nice UI which works nicely with the Mac's Automator and iPhoto (Pixelmator). At the beginning the slick look and feel of Pixelmator won me nearly over and I considered it to pay $60 for a license pretty seriously. Then I started to do my first image which was to create an image which contained the company image and logo for the normal and one for the selected state. For the selected state I wanted to create a button with rounded edges.
These are the steps to create that image and in both tools these steps were quite similar probably because both of them got the same inspiration from Adobe's Photoshop:
Everything was homing along until I hit the issue with the Rounded Rectangle shape. There I was not able to create that with Pixelmator even though later I learned that there is a way using the Refine Selection to create them. In GIMP that was a none issue because the rounded corners where available as tool options and this steps was done right away.
Conclusion:
GIMP: a powerhouse indeed which great features allowing precise editing (as far as I could evaluate). The drawback is that it is an X11 application meaning that it does not follow the Apple's keyboard layout and program design. Especially if for any reason X11 goes corrupt one has to restart the Mac (happened for me using Inkscape).
Pixelmator: nice, slick and slimed down to the average user needs. So if you are requiring a Mac OS X UI and are willing to pay $60 then it is worth it.
My Verdict: I will keep using GIMP but keep an eye out on Pixelmator. For now the eye candy is not worth $60 because I still would need GIMP from time to time.
Have fun - Andy
Last Monday I gave a presentation about Subversion at the Pasadena JUG and I thought now I know Subversion pretty well, As life goes Subversion did not return the favor and I am fiddling around with it even though in my book the given task should be easy but because it is a rare scenario it is not well documented.
What I want to do is to extract a project from an Subversion repository to put it into its own. Now that might sound easy but I wanted to make it clean while still preserving the history. After failing with svn copy I looked into svndumpfilter to see if it would do the trick. In theory it does but not in a real work project. The problem I encountered was that the commits where out of order making it fail when trying to include a branch. Through a short but helpful website I learned that I should not include parts but exclude the unwanted directories preserving the order of the commits and hopefully making the extraction work.
Unfortunately this means that we have to create a file containing a long list of paths to be excluded (long list of projects, tags and branches). After that we should be able to finally load the cleaned up repository through the dump file. The above mentioned web site also points out that one can drop empty revisions and renumber the revisions making it look more like a single project repository.
This weekend I will go over the presentation and publish it on our wiki.
Cheers - Andy
As mentioned in the previous entry I was setting up a build system for my current project. I tried out Anthill (community and Pro version), Cruisecontrol, Continuum and TeamCity (Jet Brain) and now I tried out Hudson. Personally I would prefer TeamCity but that is not open-source even though there is a free version available. But right after that come Hudson which is easy to use, easy to setup and works quite nicely. The only shortcoming of Hudson compared to TeamCity is that a build is one job and if I build different releases of the same project I would need to duplicate the jobs which is not a biggy but if you change VCS or alike then you need to change that in all jobs using that.
Setting up Hudson is as easy as dropping the WAR file into a deploy directory and optionally setting the directory in the environment variable HUDSON_HOME where Hudson should keep its data. Then fire up the web server, log into http://localhost<:port>/hudson and you are in business. It is a good idea to specify JAVA_HOME so that Maven does not fail if you use Maven. Go to the Manage Hudson -> Configure System and set the paths to Maven and Ant. Then create your first job and hit build now, done.
In order to make it easier on developers to use not publicly available Maven artifacts like ojdbc, quartz or even Flex SDK it would be great to have an internal Maven repository. This way such artifacts only need to be uploaded once and not per developer. Earlier I just created a directory listings in a web server but now I found a tool that is easier to use and can even speed up download time by caching remote artifacts on its server. This tool is called Artifactory by jFrog.org. It is a little bit more difficult to setup but it is worth the effort.
First download the tool from jFrog.org's website and put it into the deploy directory of your web server. Then adjust the web server configuration and I use JBoss here which needs only some minor tweaks on the run.conf file inside the <jboss.home>/bin directory. First increase the JVM's available memory and also set the Perm Size otherwise you will run out of memory:
-Xms512m -Xmx1024m -XX:MaxPermSize=128m
Then you need to tell JBoss to use the JVM MBeanServer with:
-Djboss.platform.mbeanserver
Now you can fire up JBoss, open http://localhost<:port>/artifactory<-version number> and log in as amin/password.
First I created a local repository (in the admin tab) to make sure I can deploy my own artifacts there including artifacts not available in public Maven repositories. Then I uploaded (in the deploy tab) these artifacts. Then I added some additional remote repository according to my POMs. Finally I added my local and all the necessary remote repositories into the already defined virtual repository called remote-repos. The idea is that I can use one repository in the POM's repository list instead of listing them all one by one. Now if I add this repository in the POMs as the top repository and keep the previous repository in the POM listed below I will be able to access the public Maven repository even when I am outside of the internal repository's network.
Beside that I can browse the repositories, search for artifacts quick and easily and even remove cached stuff. Overall that tool is good as gold and does a great job.
Have fun - Andy
Earlier I learned that MySQL only provides foreign keys on the InnoDB storage engine but now I ran into even more troubling issues with MySQL. That makes me think how could Sun pay all that money for such a toy database. I know that MySQL is the de-facto standard as Web database but like Windows this does not say anything about its quality.
Well, I was trying to install a build system and after making a passwordless CVS access working I though I would be done but MySQL took the most of time to make the build running smoothly including the tests where the DB is used. I ran into two major issues:
The first issue is problematic because I need the test to run against the local network loop (127.0.0.1) so that the test run smoothly on the developers' computer as well as on the build system. On the other hand this box has no VNC as so I need to use the MySQL administration tool on a remote computer with a UI. This means that I have to switch the assigned network address when I want to administer the DB making the build fail in the meantime.
The second issue is bad because now I have to make sure that my code only uses lower or upper case for table names including tools like dbunit. This is annoying because I don't know of any other DB that does this that way. I never paid attention to the case of table names etc in a SQL / JDBC statement and I think nobody should. I fixed that by making MySQL case-insensitive for table names by adding this line to the my.cfg configuration file that on Linux is normally under /etc directory:
# Make sure that MySQL uses lower case to identify objects (otherwise the names are case sensitive causing all kinds of problems)
set-variable=lower_case_table_names=1
In addition to make sure that I have foreign keys available I had to add this line in the my.cfg file as well:
# Make InnoDB the default storage engine for referencial integrity
default-storage-engine=INNODB
Eventually that did the trick but comparing that to PostgreSQL this is just plain ridiculous where I never encountered issues like that.
Have fun - Andy
Well, the end of last year was quite busy finishing a project and making it go live and then all the Holidays' activities. The New Year started fine but now all but one of my kids are sick.
That said I finally started to use MythTV to watch the postseason Football games and it is nice to watch them after the game ended because then I don't have to watch any of the countless commercial breaks. This cuts a 3 /12 hour game down to a little bit more than 1/12 hour.
While finishing the project last year I learned a lot about Hibernate and the pros and cons of it. The biggest problem is that the design of the Entities are made early on but the performance issue will not arise until late in the project. Having nobody on the project with enough experience designing the entities a lot of time will be spent at the end of the project to resolve performance issues because many of the issues cannot be resolved without code changes.
For example a User with Regions, Roles, Addresses will build up quite a graph. In a Web project the data must be loaded fully before it is handed over to the website meaning that all the data must be fetched from the DB. With eager loading most of the data can be fetched with one query but with the drawback that all the data is loaded even if not needed like when the User is just a reference in another object and the only thing needed is the key, first and last name. Especially if the Entities and referenced Entities are referring to many other Entities that can pull a lot of data and then creating all the mapping Java instances. Using lazy-loading could elevate that problem but it would yield many subsequent queries if all the data are needed. Now Hibernate allows me to fetch the subsequent data at the same time programatically but these are only loaded in additional queries (trips to the DB). The only way to handle this is to have different Entities which different degree of loading referenced data. But that in turn has a deep impact into the code requiring some major code changes. This is especially problematic if Inheritance is used because that would prevent the developer to create a light and full Entity based on the same base class. I will talk about this later in a more elaborated entry.
Finally after more or less 2 years I finally managed to clean up my office. Because it is the only room in the first floor where the kids have no access to it ended up to be a storage room for computer equipment but also for other stuff. Eventually I created a list of steps to clean up the room and eventually it was done. Now the next project of that kind is cleaning up the garage with is way more challenging.
Happy New Year - Andy
After having my family sick for 5 days I eventually found some time to play a few hours and went back to Halo 3. Coming back after quite some time I started to try out some new moves and strategies. Then I came up with the idea to try to finish a mission without dying along the way. That said I wanted to start with a really hard mission and that was Crow's Nest. The problem with that mission is that it contains a least two battles that are really difficult. The first is initial battle in the hangar which has several waves of enemies and the ammunition is limited. The second is in the Motor pool where the is a horde of brutes including a brute chieftain with a deadly gravity hammer.
The battle in the Hangar is difficult because there are many hallways, corners and levels so that it is easy to get caught off guard or pined in a corner dying pretty fast. Trying to survive I figured out a nifty strategy that makes is nearly fool proof. First I enter the hanger through the right door, kill the grunts and make my way up to the upper level and move to the left immediately. From there I decimate the enemies using the battle riffle or the carbine. I focus on the brutes first and some of the close grunts. The rest is taken care of by the other marines. There it is also easy to evade the shots by the enemies and the Covenants phantoms. The only enemy that come up to this level is a grunt that comes from the right side. From time to time you might want to roam around to find find more ammunition like a needler or others. The last wave of brutes / grunts will stay on the floor of the hangar and so you can run around to find ammunition to take them out. When done go down to the hanger's floor and pick up a needler and fill it up. Then see if there is a turret around and if pick it up for later fights.
The next fight is in a cave right before the ops-center where a bunch of flying drones fight you. In the little room at the end of the hallway where you enter the cave there is a rack with battle rifles where you can get one and reload it. Because that crate fell over I could not hide behind and so I went back into the hallway taking the drones out. It turned out that the drones are not shooting at me if I am back in the hallway. There I could take out most of the drones without getting shot at. Then I picked up the turret again and made my way to the ops-center and to the hallway that leads to the motor pool. In this hallway I drop the turret, go back to the cave and pick up the turret on the right hand side and bring it back to the hallway.
Finally the battle in the motor pool is still difficult but I figured out some tricks to increase the chances to survive. First I open the door, drop the turret behind the shield and move forward to the ramp while switching to the needler. Either I throw a grenade or use the needler right away to take out one or two brutes. While being close I use the needler to take out the brutes. If I am in troubles I run back on jump through the hole in the orange metal wall and got behind the shield. Then I use the battle rifle to take out the brutes. First I focus on the golden brute with the brute shoot. Then I go to the left of the shield and take aim on the golden containers at the other end of the motor pool which will explode when shot at. This takes out some the right shield exposing the chieftain better. For some time there are no new brutes coming carrying carbines and I try to take out the chieftain with the battle rifle. Sometimes that works fine. If the brutes with the carbines appear or I run out of ammunition on my battle rifle I got right through the hole in the wall to the crate and fill up. As soon as the brutes with the carbine appear I retreat into the hallway to avoid their fire (high enough or into the left or right corner). From there I use the battle rifle to take them out one by one retreating back as soon as I am shot at but keep an eye on the chieftain or other brutes that may enter the hallway. If the chieftain comes to the hallway use grenades and battle rifle fire to keep him out and kill him there. If he enters run towards him and melee him several times until he is dead. It seems that he cannot swing the hammer while punched. When he is gone and everything seems quiet take a gravity lift (in front of the shield) and go up to the upper walkways. Be careful because a brute or two could still hide out. When all brutes are gone, reload the battle rifle, take the gravity hammer and the turret with the most ammunition. The turret helps greatly against the flying drone on the way to the barracks and to kill the brutes afterwards.
Have fun - Andy
This week I was confronted with a challenge to figure out when Hibernate does update a record and when not. The problem was that we had to know when Hibernate does update a record because of a version flag we are going to use for optimistic locking. The import thing was that a master record is not updated when a child record is updated and that a record is not updated when its content was just reset.
Most of the results where quite good and helped us a lot to keep changes at bay. Hibernate does not update a record even when its content is reset even when a string value is set of a field that has a different address as long as the content is equal. Also when a child is updated and its saved through its master record only the changed children records are updated. This enables two users to change different child records and safe them without any exceptions. Because we are using a Hibernate Interceptor to set an updated date field the field is not set and therefore the record isn't updated when the content has not changed. Using the Hibernate Interceptor really makes life really easy here.
Eventually I found scenario where it did not work out as expected. In as One-to-Many (and I also think in a Many-to-Many) relationship adding or removing a child makes Hibernate updating the master record even though on the DB nothing has changed for the Master. Removing the child directly from the DB and then re-fetching the master record does yield the same result but without the update of the master record. I don't know why the master record is updated and I think Hibernate should be able to detect this and don't do an update. It could be that there is a way to prevent that but for now I don't know how.
Cheers - Andy
Tonight I will give a presentation about Liferay on the Pasadena JUG. It will tackle how to setup a website using Liferay 5.1.2 including creating your own plugins using the Plugins SDK.
When I started using a Mac with OS X I had a lot of problems with the Finder. Changing to the Mac was mostly easy and provided a lot of useful tricks to speed up tasks on a Mac. That said this did not apply to the Finder and even today I end up with gazillions of Finder Windows when I finally shut down the Laptop. Briefly I had a look at Path Finder 4 but this version had not enough added value for its prize tag. A few days ago I saw that Cococatech released version 5 of Path Finder. This time it seems way much better than the earlier version and includes a lot of useful features. This includes:
I just started to use it and so far it seems to be a little bit overwhelming. Still I like it a lot and I am looking forward to buy it if it fits into my daily business and I think I know that when the 30 days trial is over.
So Good-bye Finder and Hello Path Finder - Andy
Well, this week I tried to make a bread in a form, let it rise there and then put the loaf inside the form into the cold oven and then start to heat up. This lead to a bread with much more air in it but it had the toast like feeling with sides and the bottom being more or less white.
I am thinking using another form to put the bread into. This is called rehrucken and is a half-round, lengthy form with large ripples. Putting a parchment paper into the form the bread will not go into the ripples but the ripples will allow the hot air from the oven to circulate under the bread making sure that the bread is backed at the bottom as well.
Slowly but surely I feel like Dr. Frankenstein working in my lab to worm the secret out from mother Nature on how to back Swiss style bread (or at least what I am used from my childhood).
Cheers - Andy
The first project I used Spring Security (formerly known as ACEGI) the setup was so complicated that we used the Spring Bean format from the beginning. In the new project I am working on the Spring Security was setup with the XML Namespace configuration which looks like this:
<security:http auto-config="true"
<security:intercept-url pattern="/images/**/*" filters="none"/>
<security:intercept-url pattern="/secure/**" access="ROLE_AUTHENTICATED"/>
<security:intercept-url pattern="/help/**" access="ROLE_AUTHENTICATED"/>
<security:form-login login-page='/login/loginRequired.action' authentication-failure-url='/login/loginFailure.action' default-target-url="/login/login.action" always-use-default-target="true"/>
<security:logout invalidate-session="true" logout-success-url="/login/logout.action"/>
<security:concurrent-session-control max-sessions="1"/>
</security:http>
But that leaves me with little room for customization. Well, a few hours digging around in Spring Security and I finally found several ways to customize the configuration setup.
1. Custom Authentication Provider
One of the most important part of the Spring Security setup is the Authentication Provider and not everyone is happy with the default. In order to have my own Authentication Provider used I only need tag the Authentication Provider bean as such with the custom-authentication-provider element. This looks like this:
<bean id="daoAuthenticationProvider" class="com.wb.ads.pp.util.WBAuthenticationProvider">
<security:custom-authentication-provider/>
<property name="userDetailsService" ref="userService"/>
</bean>
2. Custom Access Decision Maker
This is for whatever reason an attribute on the HTTP element and takes a reference to your implementation:
<security:http auto-config="true" access-decision-manager-ref="accessDecisionManager">
3. Custom Filter
You only need to tag your filter with custom-filter element and add an attribute before or after with the predefined filter name that goes after or before your custom filter:
<bean id="wbppDebugFilter" class="com.wb.ads.pp.util.DebugSecurityFilter">
<security:custom-filter before="CHANNEL_FILTER"/>
</bean>
Have fun - Andy
In a piece of Wired.com the self-proclaimed 'hater of all free' Author Andrew Keen says that the economic downturn will pop open-source. It seems that Andrew has quite a short memory and even if the problem with the economy seems to be much worse that when the Internet bubble burst we had such a crisis back in 2001 to 2003. Even though I lost my job in the fall of 2002 I started to work for an open-source project called: JBoss. Today I still profit from the work and money I put into this endeavor.
Of course the economic downturn with have some implication onto the open-source but maybe not in such simple turn as Andrew thinks. But even if developers of open-source projects are laid of their chances to get another job is much better than for the people that just had a nice-to-five job. That in turn means that open-source will not falter because of a max exodus of their developers. On the other hand companies need to save even more meaning that they are considering open-source more and more making the open-source business model even more successful.
I would predict that the open-source movement will become stronger despite or maybe even because of the economic crises.
Have fun - Andy
Yesterday I tried to back another piece of bread based on the same dough as on Sunday which is white flour with enough water to make a good dough, some yeast and sugar as well as some salt. This time I let the dough rise several times and even let the loaf o bread rise quite some time before putting it into the oven. Even the dough was a little bit fluffier it is still far away from what I am looking for. The next time I am going to try it by putting the loaf into a cold oven and then start to bake it. This should give the yeast more time to great bigger bubbles.
I am also thinking of putting the dough into a form and let the dough rise in a warm oven. The form should prevent the dough from flattening out and the heat to make the yeast build up enough gas to great bigger bubbles. Eventually I could turn on the oven to baking heat avoid to move the dough and losing the bubbles in the process.
Have fun - Andy