<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6353248423786035448</id><updated>2011-09-23T15:02:19.101+01:00</updated><category term='dependecy inversion'/><category term='refactoring'/><category term='python'/><title type='text'>Difficult Conversations</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://petewood.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6353248423786035448/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://petewood.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Peter Wood</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6353248423786035448.post-1046141088245131998</id><published>2007-10-14T21:37:00.000+01:00</published><updated>2007-10-14T23:27:59.848+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='dependecy inversion'/><title type='text'>Long road to dependency inversion</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;I have been working on some code that was given to me to optimise. The problem was that with a few cases it took about 30 seconds but with 20 times that it was taking 80 minutes and using up all available memory. I hadn't worked on the code before and it was basically a Python script with one big loop of about 400 lines with 2 more nested loops. The tabs were set to 2 spaces which was difficult to read. There were two little helper functions; everything else was global. There were no functions worth running the profiler against. The heritage language before Python was a Fortran derived language.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;So I did what I usually do with code that isn't mine. I started cleaning it up, extracting functions, getting rid of globals, renaming variables. The basic extractions I performed were:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul style="font-family: trebuchet ms;"&gt;&lt;li&gt;Everything from the global namespace into a main function.&lt;/li&gt;&lt;li&gt;Contents of each loop into its own function.&lt;/li&gt;&lt;li&gt;Any branch with more than a few statements in it into its own function&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: trebuchet ms;"&gt;This broke the code up into manageable chunks. I was able to spot some unnoticed duplication and remove it. I got a grasp on the meaning of the chunks and made them more Pythonic. I started feeling I could breath a little more.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;I found the calls that were being made multiple times in the innermost loop and cached them so they were made once. This fixed it so that it took about 40 seconds. Not bad. So I passed the code along to my colleague.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;The thing is though, I felt really dissatisfied with the code. I'd extracted functions and simply passed them the parameters they needed. The functions that had been in the innermost loops took a large amount of parameters, and they were carried through from all the outer loops. Many of the functions took more than about 8 parameters. It was easy enough extracting them because I was just making it work. Reading the code afterwards was convincing because I would read the function name and the parameters it used to get a sense of what the function was doing and the dependencies were explicit, that's a good thing, right? The thing that made my heart sink was the thought of my colleague having to use these functions with 8 or 10 parameters. It just wasn't right.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;I realised that I'd just done divide and conquer but without stepping up to abstraction.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;So I started looking at the data that was being passed into functions. Some was constant over the loop, so instead of passing it all to the function I made a class containing it and passed that in instead. So each function took a 'static' parameter and variable parameters for the loop.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Then I looked in the function and found what the 'loop static' parameters were being used for. If they were used for a branching decision then I made that decision in the constructor of the class instead and created a function object to perform the correct branch operation. The function object was passed any extra needed parameters (usually the loop varying variables).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;The effect of applying these two rules was to simplify the logic of lower functions by removing branches that didn't need to be evaluated over and over and remove the unneeded parameters. It was far more readable.&lt;br /&gt;&lt;br /&gt;I also started to replace some of the conditionals that used the looping variables. The looping variable became another class which was initialised with a function object. I didn't take this all the way through the code, but if I had I would have moved all the conditionals to the outer loops where the code talked to the system. This is the effect talked about by &lt;a href="http://silkandspinach.net/2004/07/16/hexagonal-soup/"&gt;Kevin Rutherford&lt;/a&gt; and, as Michael Feathers &lt;a href="http://blog.objectmentor.com/articles/2007/06/05/are-else-blocks-the-root-of-all-evil#comment-395"&gt;comments&lt;/a&gt;, 'there is something sublime' about it.&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6353248423786035448-1046141088245131998?l=petewood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://petewood.blogspot.com/feeds/1046141088245131998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6353248423786035448&amp;postID=1046141088245131998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6353248423786035448/posts/default/1046141088245131998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6353248423786035448/posts/default/1046141088245131998'/><link rel='alternate' type='text/html' href='http://petewood.blogspot.com/2007/10/i-have-been-working-on-some-code-that.html' title='Long road to dependency inversion'/><author><name>Peter Wood</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
