Pages

Tuesday, May 1, 2012

Are Good Programmers Good at Maths


I was reading an interesting argument on SO. The topic of discussion was that conventional wisdom suggests that good programmers are also good at math...Or that the two are somehow intrinsically linked. Many programming books I have read provide many examples that are solutions to math problems, or are somehow related to math as if these examples are what make sense to most people.

So the question is: do you have to be good at math to be a good programmer?

It all depends on what you want to do as a software developer.

If you want to go into graphics, you need a strong background in geometry, linear algerbra, matrix tranformations, (physics wouldn't been terrible either) etc. If you want to go into SQL or other types of database programming, logic (proofs, inference laws, etc) and Discrete Mathematics (maybe even lambda calculus) are all necessary.

As far as being a programmer in the business world goes, I would say that the answer is NO. You can become a great programmer without knowing advanced mathematics. When you do end up having to deal with math, the formulas are usually defined in the business requirements so it only becomes a matter of implementing them in code.

How about a Math mindset?

Most people think of math as doing arithmetic or memorizing arcane formulas. This is like asking if you need perfect spelling or an extraordinary vocabulary to be a good writer.Writing is about communication, and math/programming is about the process of clear, logical thinking (in a way that you can't make mistakes; the equation doesn't balance, or the program doesn't compile). Specifically, that logical thinking manifests in:


  • Ability to estimate / understand differences between numbers: O(n^2) vs O(lg(n)), intuitive sense of KB vs MB vs GB, how slow disk is compared to RAM. If you don't realize how tiny a KB is compared to a GB you'll be wasting time optimizing things that don't matter.
  • Functions / functional programming (is it any coincidence that the equation f(x) = x^2 is so similar to how you'd write that method? The words "algorithm" and "function" were around in the math world far before the first computer was born :-))
  • Basic algebra to create & reorder your own equations, take averages, basic stats

So, I'll say you need a math mindset, being able to construct & manipulate mental models of what your program is doing, rather than a collection of facts & theorems. Certain fields like graphics or databases will have certain facts you need also, but to me that's not the essence of being "good at math".


I'll quite happily admit I've never particularly liked maths or been good at it (I actually graduated with a degree in Political Science!) and have worked as a professional developer for over 18 years now. I develop mostly web applications, which rarely require that much maths. More important is the ability to think logically, be able to break problems down into chunks and have a wide understanding of the various technologies and frameworks involved.

As a programmer you are much more likely to have to implement an existing algorithm than devise an entirely new one. Need to work out, say, compound interest? You don't need to figure it out yourself, just look-up the formula and apply it. Most of the problems have already been solved, you just need to know how to implement the solutions in your language of choice. That's not to say that being good at maths wouldn't be an advantage; it's just that it isn't totally essential.

When I was at school in the mid 80's when home computers where not very common I often wrote programs to solve my maths homework. I often couldn't do it in my head, but I could apply whatever formula was required as a software routine. You don't need to be another Pythagoras to work out the longest side of a right-angled triangle, you simply need to be able to code up a² + b² = h² in your language of choice.

Conclusion

You don't have to be good at math. However, you have to be good at logic, and problem solving. Some would argue that people who are good at logic and problem solving are usually good at math also. I would say that it really depends on the type of math. You can be terrible at calculus (like me), and still be a good programmer (like me). But if you have trouble with Discrete Math and Set Theory, you would probably find a lot of aspects of programming quite hard.

Wednesday, March 7, 2012

Honey, I Introduced Agile In My Company


People are always resistant to change, and moving to scrum is a pretty big one. Motivation and direction are key.

My group has recently grown in size with the addition of several teams from different projects. We work using an Agile programming methodology: 2 week sprints, deliverable every sprint, 2-3 pushes to production every sprint for each team. A challenge we face is to "convert" the newly added teams to this methodology and way of thinking with as little trauma and resistance from the members of these teams.

The first step is to get people motivated to give scrum a chance. Start with people who you feel will be receptive to the change whether they are developers or managers, so you can build some momentum. Getting managers on your side going to be a necessity at some point, but how you handle that depends on your environment.

After that, everyone needs to be trained, whether it means reading a book or having a lecture series. Unless people know how scrum works, you cannot start trying to implement the process. They won't "get it" right away. That doesn't matter -- explanations don't really help as much as simply doing it. Get them started with daily standups today. Immediately. No waiting around. No "conversion". Just start.

Agree to just one sprint to get started with a reasonable scope of work. They'll completely mess it up, but that's okay.


The best way to learn Agile methods is to just start doing Agile methods.

Here are 6 practical tips that may help you out
  • First get management backing. If you don't nothing else will make up for this one.. If the upper level is all 'The deadline is yesterday..', 'Working weekends for the next 3 months', 'Why are you writing tests when you should be coding?.. we can test later.' The dodo simply won't fly.
  • See if the culture of your organization is suitable for agile. This was something I missed.. To borrow a line from the book.. The process will be easier-faster if the culture supports and nurtures new ideas, allows time for people to learn and do new things, is patient enough to support innovations with long term benefits and does not consider failure to be a death sentence
  • The People: Identify the innovators : early adopters : early majority : late majority : laggards ratio. The first 3 are your target audience initially.. should be around 30-40%.. that gives you the critical mass to get rolling. The trouble is Agile turns the spotlight on the elephants in the room.. deficiencies and issues become easily visible.. if you live in a place which has had a "Bozo Explosion" (to quote Guy Kawasaki's term), the change would be really slow and painful.. if at all. We have a tendency to assume that if an idea is good, it'll be accepted. Not true. Lots of sociological reasons raise their heads.
  • Next don't try too many things at once. Take it slow.. take it easy. The trick is to use a refactoring-legacy-code-like approach. Find little wounds here and there and patch them with an agile bandage. Make sure that the people understand the practice and benefits and they should adopt them over time. Not everything will stick but soon it becomes better on the whole. How soon depends on a number of variables some of which are out of your control.
  • Its a huge personal investment to make this happen. Re-examine if you are willing to make this committment and go through the ups-and-downs it brings. Also you may have to hand over the baton to someone else or a higher up.. Be prepared to relinquish change ownership for the greater good. Don't fall into the 'Its my baby' syndrome.
  • Agile is different for each team, each organization. Not everything you read/propose will work.. let acceptance guide you towards the things that will work for your scenario. Find other ways that compensate for the practices that didn't take root.

You can't heal what you can't feel

Building trust with you team members and keeping them motivated is of utmost importance. Once people are motivated and have an idea of what they need to do, you need to have your first planning meeting and set up the necessary parts of scrum (scrummaster, daily meetings, etc.).

I would expect that the first planning meeting will not go smoothly, and will be a learning experience for everyone. Also the first few sprints will be very rocky, and probably behind schedule. The key part now is discipline and persistence. Do not let daily meetings run too long, keep the planning meetings on task, and make sure everyone is doing their roles correctly. With past successes and having the trust of both your team and your manager, they will look to you when it comes time to make decisions.

Lastly I'd just say be very empathetic. I made the mistake of dismissing most ideas before I'd really though them through because I didn't read about it in "XYZ agile book." Listening to your team & trying to implement some of their suggestions will go a long way.

Agile for small teams of 2-3 people

If you are a very small team of 2-3 people, you sure can use certain agile principles in your projects, you don't have to use scrum, use whatever will work best for you. You can definitely benefit from some of XP methods and some scrum practices. But probably not "by book", 1-2 person team is just too small even for that little overhead scrum brings, start with what book says and then drop whatever you'll feel irrelevant after some time. Just don't drop retrospectives, it sure is worth the time spent discussing the problems you have, and finding solutions for them.

Agile techniques are suited to smaller teams as with larger teams it becomes more difficult to manage communication. With 1 or 2 people developing a project (and a customer) you should be able to work in an agile manner very easily. i suggest you read the agile manifesto as a good start to agile. For scrum, I'd suggest you look at Scrum from the trenches. Kanban seems to be in fashion now and there is a personal Kanban too!

Agile for the Solo Developer

Here are some tips to implement Agile processes for the solo developer:
  • By doing test-driven development
  • By developing in small sprints, maintaining a sprint burndown and a product burndown - A sprint burndown starts with a list of all tasks you've decided to complete in this sprint (a subset of your product backlog to be completed over a set period of time - e.g. 2 weeks) along with the estimate of the work required. As you mark things off, you mark them as done; thereby reducing (or burning down) the remaining work for that sprint.
  • Similarly, a product burndown tracks the remaining work for the whole product backlog
  • By having a lot of contact with the customer
  • Keeping a product backlog - A product backlog is basically a list of all items you intend to complete at some stage for this product.
  • Adopting the concepts of relative estimation and velocity - Relative estimation is an estimation technique that uses the other tasks (or stories) as a guide. For example, if you know task A is easier than task B and about as twice as complex as task C, you'd make sure the "points" for task A were correct relative to those expectations. The emphasis is not on correctly guessing the amount of work required, but keeping estimates consistent with each other. Velocity is a measure of how many "points" you get done in a sprint. If your relative estimation is ensuring consistency, this velocity can be used to estimate which tasks you're likely to get done in the upcoming sprints. Note though that velocity should be constantly revised.

 I found this conference talk which should help you out: Personal Kanban: Optimizing the Individual Coder

Personally, I have seen more abuses in the name of agile than I care to write on. Many times "we're doing agile" means "we're throwing away all semblance of process and doing what we want, Yeehaw!" (for the obvious cowboy reference). An agile environment definitely helps, but you have to allow for developers to talk to each other and hammer things out--without scrum dictator approval.

Agile is about incremental development in a field of changing requirements, not about dictating people how they individually go about doing their work.

References: Practices of an Agile Developer, Collaboration Explained, Agile Retrospectives: Making Good Teams Great, Stackexchange, Agilescout

Wednesday, January 25, 2012

Pattern Matching and Guards are Fundamentally Different


Pattern Matching and Guards are fundamentally quite different! At least in Haskell, at any rate.

Function using pattern matching

check :: [a] -> String
check [] = "Empty"
check (x:xs) = "Contains Elements"
Function using guards


check_ :: [a] -> String
check_ lst
    | length lst < 1 = "Empty"
    | otherwise = "Contains elements"

Guards are both simpler and more flexible: They're essentially just special syntax that translates to a series of if/then expressions. You can put arbitrary boolean expressions in the guards, but they don't do anything you couldn't do with a regular if.

Pattern matches do several additional things: They're the only way to deconstruct data, and they bind identifiers within their scope. In the same sense that guards are equivalent to if expressions, pattern matching is equivalent to case expressions. Declarations (either at the top level, or in something like a let expression) are also a form of pattern match, with "normal" definitions being matches with the trivial pattern, a single identifier.

Pattern matches also tend to be the main way stuff actually happens in Haskell--attempting to deconstruct data in a pattern is one of the few things that forces evaluation.

By the way, you can actually do pattern matching in top-level declarations:

square = (^2)


(one:four:nine:_) = map square [1..]


This is occasionally useful for a group of related definitions.

GHC also provides the ViewPatterns extension which sort of combines both; you can use arbitrary functions in a binding context and then pattern match on the result. This is still just syntactic sugar for the usual stuff, of course.

As for the day-to-day issue of which to use where, here's some rough guides:

Definitely use pattern matching for anything that can be matched directly one or two constructors deep, where you don't really care about the compound data as a whole, but do care about most of the structure. The @ syntax lets you bind the overall structure to a variable while also pattern matching on it, but doing too much of that in one pattern can get ugly and unreadable quickly.

Definitely use guards when you need to make a choice based on some property that doesn't correspond neatly to a pattern, e.g. comparing two Int values to see which is larger.

If you need only a couple pieces of data from deep inside a large structure, particularly if you also need to use the structure as a whole, guards and accessor functions are usually more readable than some monstrous pattern full of @ and _.

If you need to do the same thing for values represented by different patterns, but with a convenient predicate to classify them, using a single generic pattern with a guard is usually more readable. Note that if a set of guards is non-exhaustive, anything that fails all the guards will drop down to the next pattern (if any). So you can combine a general pattern with some filter to catch exceptional cases, then do pattern matching on everything else to get details you care about.

Definitely don't use guards for things that could be trivially checked with a pattern. Checking for empty lists is the classic example, use a pattern match for that.

In general, when in doubt, just stick with pattern matching by default, it's usually nicer. If a pattern starts getting really ugly or convoluted, then stop to consider how else you could write it. Besides using guards, other options include extracting subexpressions as separate functions or putting case expressions inside the function body in order to push some of the pattern matching down onto them and out of the main definition.