Adept Software Development

Adept: (A)pplication (D)evelopment (E)nterprise to (P)ersonal (T)ransition. It is a system I am developing to leverage Enterprise developer skills to produce stand-alone software for other market segments. This is a general software development blog discussing issues about project, architecture, design and development. The emphasis will be in Java, but many of the issues will be more general. Almost all will be technical.

http://marringtons.com

Friday, September 03, 2010

BDD, FitNesse and the SDLC - The Triggers

My two main areas of interest in my software design career has been user interaction and an integrated SDLC. For now I am going to talk about the latter.

When developing projects alone, the difficulties were minimised. I am good at all the tasks from requirements gathering (one of my favourites) to release. Anything not recorded in writing was still in my mind and would come to light during design or development.

Over the last decade I have been involved in, run or managed larger and larger teams. I have always wanted to connect procedures from requirements gathering all the way to release testing in a way that is suitable to all parties and consistent (read automated). On the way I have...

... Unit tested everything. I originally experimented with my Adept libraries. I found a few problems, but not many for the effort involved. And the upkeep as I refactor or add to the library was unmaintainable. When you are designing you don't want to be distracted with testing. This was prior to TDD (Test Driven Development). I then worked with teams that required full unit testing. As 2IC I was responsible for code reviews. Developers don't have the incentive to write good tests nor the data to write meaningful tests. It is obvious that unit tests only work if they are part of the design, not the implementation. Enter TDD. I insisted on unit testing on the last project I lead in 2006/7. Unit testing is better than no verification prior to release. For my own code I no longer write unit tests. The benefits are few for such a large overhead.

... XP (eXtreme Programming). I have implemented facets of XP over the years. I have also worked with people who have treated it as dogma - and turned off their brains in favour of following XP to the letter. I managed a team using XPlanner a few years ago and liked the results. The morning and iteration end meetings were very valuable and I was able to use the story-card and iteration data to satisfy the progress reporting needs of project managers and clients.

... TDD (Test Driven Development). I could never 'get into' TDD personally. When I was in the throws of software design I did not want to think in terms of tests. Too much wood not enough forest. I did have the opportunity to see it in practice with an XP specialist. This confirmed my view that it was too slow and ineffective.

... BDD (Behaviour Driven Development). So, how does a name change help? Conceptually I like the perspective. I felt no desire to us it while it had to be from a code developer perspective - such as rspec. Cucumber and Concordion both connect specifications from a higher perspective to be implemented. Tempting, but still a bit of a straight-jacket.

... UI Design during discovery phase. For projects with considerable data entry I worked a system where the UI could be instantaneously and easily by the BA so that the customer could get instant feedback. It is part of discovery because the customer understands their requirements better after hands-on interaction with an unbuilt system.

... Used Fitnesse as an integration test tool during a late testing phase of a big project.

... Read up on BDD - specifically this article on BDD in the analysis/design phases - http://blog.dannorth.net/introducing-bdd/.

... Reviewed the latest FitNesse updates to support BDD - plain text tables and scenarios.

At last almost all the frameworks and tools are in place for me to realise my desire to automate connection in discovery, requirements gathering, analysis, architecture, design, built, release, support and update phases.

Over the next period I will be putting together the concepts and tools for BDSDLC (Behaviour Driven Software Development Lifecycle).

Wednesday, September 01, 2010

The Wiki Mindset

Note: This was written in 2007 and left in my drafts. Forgive me if it is not complete. Everyone who has read a popular book on the Internet knows that it was invented by researchers at university as a means to communicate and share information. It was only when the popularity of the medium caused it to leak out into the wider world that we can to accept it as a read-only system. After a decade of education we are ready for all to contribute. First with Forums, later with blogs and now with the Wiki. Each fills a different need - and here we talk about the wiki. What is a Wiki? Put simply, a Wiki is a web site where the reader can contribute, change or correct the content. Readers are no longer passive observers. They have a responsibility in improving the quality of the result. The most famous Wiki is Wikipedia (http://www.wikipedia.org/). I would like to say that a wiki works best for a small team if like-minded technical people, but Wikipedia proves that wrong. Anyone can change a Wikipedia page and the change will be displayed immediately. It is reviewed, can be removed and occasionally starts a war of words - but in general if you add value it sticks. What a Wiki is not
  • A wiki is not a multi-media web-site. To allow for maximum interaction it is primarily text with basic formatting.
  • A wiki is not for static information. No company wants their brochure changed - even if it could do with clarification.
  • A wiki is not for the users in this life. They thrive on sharing and contribution.
  • A wiki is not for private or sensitive data - all can read and change.
Who will use a Wiki Wikipedia notwithstanding, a wiki more suites technical staff. I have had more success getting developers (a notorious anti-documentation group) to use a wiki than I have had with business analysts and project managers. I don't think it is the geek factor - or not entirely. I think it is about free communication. Developers have learnt from the open source culture. Everyone gains from cooperation. Unit testing has taught them that more effort now saves time later. All that, and the passion to correct wrongs has overcome some of the dislike for documentation and made the wiki a success. Who will not use a Wiki What can I do with a Wiki Procedures Records and Notes Research Collaboration

Saturday, November 21, 2009

Simple Atom Feed in Appengine

If you feel the need to add a new feed to your site and know python, then this is a simple solution. http://appengine-cookbook.appspot.com/recipe/simple-atom-feed-in-appengine/

Monday, November 16, 2009

appengine service for google maps/earth (kml)


This example is called TripKML. It reads pre-recorded GeoPt records and generates KML for Google Maps/Earth. The basic webapp is as normal:



class TripKML(webapp.RequestHandler):

    def get(self):

        try:

            ...

        except DeadlineExceededError:

            self.response.clear()

            self.response.set_status(500)

            self.message("This operation could not be completed in time...")



application = webapp.WSGIApplication([('/service/tripKML', TripKML)], debug = True)

def main():

    run_wsgi_app(application)



if __name__ == '__main__':

    main()





First we parse the command line:



            self.traveller = User.fromId(int(self.request.get('traveller')))

            trip = self.request.get('trip')





As the code creates KML, tell the browser what do do with it:



        self.response.headers['Content-Type'] = 'application/vnd.google-earth.kml+xml'





I have attached my lightweight class for generating XML. You give it the root XML tag name and attributes. Wrap everything in a folder for clarity in the tree. The last line is XML to be inserted (saved as )



            rootElement = self.kml = xml('kml', xmlns = 'http://www.opengis.net/kml/2.2')

            self.kml = rootElement.Folder

            self.kml.name(trip)

            self.kml.Style.IconStyle(id = 'noteStyle').Icon.href(iconUrl)





My style is to read the records and have factory code to call methods based on the record type. Because most records will be of one or two types, I have cached the parser method:



            parsers = dict()

            query = Record.gql(

                'WHERE userId=:1 AND trip=:2 ORDER BY time', self.traveller.id, trip)

            for self.record in query:

                try:

                    parser = parsers[self.record.type]

                except KeyError:

                    method = self.record.type + "RecordProcessor";

                    parser = getattr(self, method, self.defaultRecordProcessor)

                    parsers[self.record.type] = parser

                parser()





A record type called "notes" generates a note indicated by an icon on the map:



    def notesRecordProcessor(self):

        self.kml.Placemark.name(self.record.title).styleUrl('noteStyle').\

            description(self.record.notes).Point.coordinates(

                "%f,%f" % (self.record.location.lon, self.record.location.lat))()





The “here” record processor does more work as it collects coordinates to make a line.

Back to the TripKml class, I also overlay kml generated by Picasa to display images:



            albums = Album.forTrip(self.traveller.id, trip)

            for album in albums:

                try:

          self.kml.NetworkLink.name(trip).Link.refreshMode('onInterval').\

              refreshInterval(3600).hreflang(\

              album.feedUri + '&alt=kml&kind=photo')

                except Exception, e:

                    logging.warning('Can\'t access Picasa album for trip %s: %s' % (trip.name, e.message))





The last thing we need to do is generate the KML and send it to the browser:



            self.response.out.write(str(self.kml))





I have attached TripKML.py as it is in use and xml.py for generating the XML.

Monday, September 14, 2009

Refactor Heaven

One of the reasons I considered creating Trogger (The Travel Log) is that it has a lot of common functionality with Golf Adept - for both the mobile application and the server side.
Modern development thinking is that we should not write code that is not needed. With modern refactoring IDEs this is now not only possible but a pleasure. Look at the history of the Golf Adept mobile code.
Originally there was
GolfAdept
Then when I needed to create a version for Android I refactored the code into
GolfAdeptMidlet (and GolfAdeptAndroid) and;
GolfAdeptCommon
Given that 90% of the mobile code for Trogger is common with Golf Adept, more refactoring was in order.
mobile.common and;
mobile.midlet.common and;
mobile.golfadept.common and;
mobile.golfadept.midlet
with a similar set for Trogger.
Modern thinking is that we should not develop, keep or maintain code that is not currently in use. It is true that almost every developer has written code for an eventuality that never happened. It is equally true that if you don't consider future requirements then your code will not be reusable.
With J2ME being an old and out-of-favour platform I needed to consider other platforms from the first line of code. This amounted to a single decision. Create a clear separation between business logic and I/O code. This worked well for the Android port. I can also automatically generate business logic code for the iPhone and Windows Mobile in C++ while only having to rewrite the much smaller platform specific section.
mobile.common has 4,869 code lines and;
mobile.midlet.common has 770 code lines and;
mobile.golfadept.common has 2,541 code lines and;
mobile.golfadept.midlet has 10 code lines
The application specific midlet code is not just a boot-strap. Platform dependent code is not clearly separated and takes up about 10% of the code base.
Because of the core common code I managed to write the base Trogger application in less than 2 days. It might take me a full 5 days to add all the frills I want.
Similar refactoring was needed for the server side (Python on the Google Appengine). I will save that for another discussion.