On Writing, Learning, and More

The problem with having a blog is that you have to post new content pretty consistently, or else it becomes just one of the 70 zillion sites on the internet that never gets updated and nobody reads. The question is, how do you always manage to have something to say on a (weekly or better) basis?

This becomes more difficult when it’s a professional blog rather than a personal one. I could certainly write a few posts about my amazing sabbatical in Europe (if you have any interest at all in history and/or castles and have the opportunity to see the Tower of London, DO IT!), my experience as a foster parent, and so on – but on a blog that’s focused on technical issues (specifically, programming and computer science) how many people who aren’t personal friends of mine will care?

Tower of London by Christine Matthews. Used under Creative Commons license.

On the other hand, if I can produce enough content that will be generally relevant to the main topics of the blog, then people can always skip the occasional diversion and come back for the next post. Which brings me back to the original question: how do I manage to consistently deliver content that the majority of readers will find useful? It’s not like I run across and solve an interesting problem every single day.

So I’m going to try a different approach. I’ll continue to do what I’ve been doing – when I have an opinion about a programming topic or just learn something I find interesting, I’ll write it up – but I’m also going to start chronicling things from my personal life that might be of general interest – like, again, what not to miss on a European vacation – even if they’re not strictly technology-related.

Additionally, I’m going to try to formalize my self-improvement program and use the blog to keep it moving. I’ve been in my current developer position for nearly six years now and am at the point where I’m comfortable with it, but even with my current responsibilities I still don’t feel like I’m really an expert developer. I’m always working to improve, but the hassles of day to day life mean that that books pile up unread and that Pluralsight subscription doesn’t get used nearly enough to justify the cost.

So I’m going to set a fairly straightforward goal: at the end of each workday, I’ll try to think of something that I learned or that became more clear to me that day. If I can’t think of anything, then I’ll pull out some type of educational material and go through it until I find something. That something can go on a list, and that list can be topics for blog posts to help me solidify things in my mind.

Maybe that won’t be anything groundbreaking. Maybe it’ll just be a better understanding of how to do something simple in TypeScript. But it seems that by doing this, I can’t help but become just a little bit better every day, and just like compound interest, all those small gains are going to build up over time.

Pretty soon I’m expecting a promotion to senior developer. My goal is to raise my skills to the point where I feel like I deserve it.

Comma placement in sql scripts

It’s a truism that old habits are hard to break. Turn down the same street every day, and you’d better pay attention if you want to actually make it past that intersection without turning! One habit I feel that I need to change is my comma placement in a select statement.

Today I’ve been working on debugging a new view I’m writing to simplify some Oracle code. I’ve taken some existing code and removed the columns I don’t need, leading to something like this:

SELECT owner,
segment_name,
segment_type,
partition_name,
tablespace_name,
FROM

Running the script, I get this error:

SQL Error: ORA-00936: missing expression

This is actually more helpful than many Oracle error messages. If you look back at the select statement, you’ll see that when I deleted the final columns, I neglected to remove the comma after tablespace_name, so Oracle is looking for another column and failing to find it. If the statement had been written like this:

SELECT owner
,segment_name
,segment_type
,partition_name
,tablespace_name
FROM

then I wouldn’t be able to make that mistake. The nice thing about this format is that no line depends on the next line, and if you add another column to the end the previous line doesn’t need to be modified. I think I have a hard time getting myself to use this format because it’s not good English – but it does seem like good programming practice.

Building a Pugly-Linked List

Meet Janie. Janie has an ever-changing menagerie of pugs, and would like to use a data structure to keep track of them. What data structure would be most suitable?

Sad pug
Sad pug image by wikimedia user DodosD. Reused under Creative Commons license.

Janie could keep her pugs in an array, but this isn’t a good choice for several reasons. Arrays are best for collections of constant size, while the size of her menagerie varies. Further, any ordering of the pugs will require re-sorting the array as pugs enter and leave, and without this ordering we lose the benefit of being able to find a given pug in O(1) time by indexing into the array.

Queues and stacks don’t have the constant size problem – we expect them to grow and shrink. However, they’re unsuitable because they define the order in which pugs have to be removed after they’re added; the oldest pug might usually tend to come off the queue first, but not always, and we certainly hope the newest pug won’t be popped off the stack right away.

Consider a linked list, however. A linked list is a data structure in which we have some number of nodes, each of which points to the next node on the list; by maintaining a pointer to the head of the list, we can obtain the rest of the objects by following the next pointers. In a doubly-linked list, each node contains a pointer to the next node and a pointer to the previous node.

We’ll modify this slightly to get a pugly-linked list. The head of each pug (its head pointer) will point towards the previous pug in the list, and the tail of each pug (its tail pointer) will point to the next pug in the list. (Normally, we’d keep one head and one tail pointer, pointing to the first and last elements of the doubly-linked list, while each node would have previous and next pointers…but we’ll abuse the terminology a bit to make it pug-specific). If the tail pointers are curly this will, naturally, give us a circular list.

If we need to find a specific pug, we can iterate through the list, which is the same thing we’ll need to do with an unsorted array – but we won’t have any empty cells from missing pugs. We just look at the first pug and follow the tail pointers until we find the pug we want. We can add pugs in constant time – just set its head to point in the same direction as the first pug’s head, set its tail to point at the first pug, and set the first pug’s head to point the new pug, which has now become the first pug in this pugly-linked list. We can remove pugs (provided we have a pointer to them) in constant time as well, by updating the next and previous pugs to point at each other rather than the pug being removed.

And this is how Janie can keep track of all her pets with a pugly-linked list.

Interfaces in C#

Consider test-driving a new car, of a make and model you’re not familiar with. It’s unlikely you’ll need any instruction in how to do it: rightmost pedal makes the car go, pedal next to it makes the car stop. Even though there are many different cars, they have a reasonably consistent interface that allows most people to drive most cars.

Subclassing Car

Suppose we want to implement this in code. Let’s say I want to use a Camry object. A Camry “is a” car, so it makes sense that the Camry class inherits (possibly indirectly) from the Car class. We would never actually instantiate a generic “car” object, so Car can be an abstract class.

What methods would Car have? Two obvious ones could be ApplyGas and ApplyBrake. Maybe they’re implemented something like this:

Car class

In this case, the comments are standing in for some code that physically allows more gas into the engine or applies the brakes. This works fine….as long as every car works exactly the same way. But what happens if we have, for example, a Prius? Now stomping on the gas pedal may or may not actually be sending more gas to the engine, which means that we need to override the behavior in the derived class. More generally, for each type of car that derives from the Car class and uses different hardware, we’ll need to rewrite the methods for that car’s hardware – and if we forget, and the method tries to use hardware that isn’t there, then things can go horribly, horribly wrong.

Ok, so we’ll make ApplyGas an abstract method; now each derived class will be forced to implement it appropriately. The same will go for StartCar (do we need a key?), ChangeGear (which gears are available?), and many of the other methods, but the Car class is accomplishing our goal of ensuring that each derived class has a consistent interface.

However, we should step back and ask – what are we gaining here? We’re not sharing implementations; we simply want a consistent interface. So…maybe we should consider using an interface?

Defining an Interface

While inheritance allows us to share behavior between related objects, an interface is simply a contract that defines certain methods each class implementing that interface promises to provide. As a driver, I don’t care how each method is implemented; I simply want to know that, given an instantiation of any class which implements ICar, stomping on the gas will make me go faster and using the brake will make me slow down. I want to learn the interface, and from that, be able to handle anvy new car that might be released.

Let’s define a simple interface for car:

Car interface

Here we’ve defined various methods that we’d expect to apply to any car. There’s a way to turn it on and off, which could be by means of a key (most vehicles), by the location of the key (Tesla), or some other method entirely – we don’t know what it is, just that there is one. There’s a way to accelerate and a way to slow down. We can get the current speed and we can change direction. As is standard practice, we’ve named the interface starting with a capital I.

Notice two things that none of the methods have: an access modifier and an implementation. Since an interface is just a contract, all methods are public by default – an implementing class can’t agree to implement the methods if it doesn’t know what they are! Similarly, the interface doesn’t define how any method is to be implemented, just that they must be.

Implementing the Interface

Suppose we go ahead and create a class that implements ICar:

Car class without implementation

 

 

 

 

 

 

 

Here we’ve made the claim that this class (unhelpfully named Program – we should really choose a better name) implements ICar, but we haven’t actually provided any method definitions, which gives us the red squigglies. Hovering over ICar shows all the methods that we’re required to implement before the program will compile. This is one of the advantages of using interfaces – we can’t possibly forget to provide a custom implementation for one of the methods and end up using the default implementation without meaning to.

If we hit control-., Visual Studio will offer to implement the interface for us, either implicitly or explicitly.

Car class implement interface

 

 

 

 

 

 

If we choose to implement the interface, then each of the required methods will be created; since all interface methods are public, that access modifier is automatically assigned. If we implement the interface explicitly, then instead of the access modifier the method is explicitly called out as being the implementation of an interface. This is important because it’s possible that our class implements several interfaces which have methods with the same signature that need different implementations; declaring which implementation the method is associated with allows us to have several methods with the name name and call the appropriate method for the interface we’re currently using.

Car class notimplementedexception

 

 

 

 

Multiple Interfaces

Let’s look at an example. Here I’ve added an interface IBoat which also has a GetCurrentSpeed method, and updated that method in ICar so that both methods return strings. Since I’ve implemented ICar implicitly, IBoat must be implemented explicitly (and Visual Studio will do this no matter what option I choose when I tell it to implement the new interface).  I’ve renamed Project to something that makes more sense (Vehicle) and written a main() routine that creates two vehicle objects, one for each of the two classes. When I run the program, each call to GetCurrentSpeed will automatically find the correct method for its interface, and in fact the boat object cannot even see the methods which are specific to the car interface.

Vehicle class multiple interfaces

 

Programming to the Interface

You may have heard that you should program to the interface, not to the implementation. This means that if we know what interface an object implements, we don’t need to know or care what the object actually is. In our example above, we know that car implements ICar, but we don’t actually need to care that it instantiates Vehicle (as opposed to ToyotaCamry, FordTaurus, etc). If in the future we decide to change the implementation of car to be TeslaModelS instead of Vehicle, we only have to change one line of code. Because car is defined as an ICar, we can only call methods defined in ICar (or Object, which ICar inherits from) on it, and those methods are guaranteed to exist in every class that implements ICar.

Thus, although interfaces can be used as a type of multiple inheritance, their real value is in allowing components to be loosely coupled: when one part of the program changes, it becomes less likely that this will result in other parts of the program needing to change, which means less work and (hopefully) fewer errors. By restricting what we’re allowed to do (in this case, restricting objects to using only methods required by the interface), we actually make those objects more usable.

When not to optimize

Software development has some consistent goals. We want the software to be as fast as possible, as small as possible, to work as well as possible, and to be done as soon as possible. Naturally there tend to be trade-offs between these goals: the fastest algorithm may require more storage space, the algorithm that requires the least space may be complicated and prone to errors, extensive testing may delay the release. We decide which goals take priority and what values are acceptable for each. But how to choose?

In some cases, optimizing for speed and size makes a lot of sense. If a loop will execute ten thousand times, a one-millisecond delay in each loop is likely to be unacceptable. If there are ten million items to be stored, requiring an extra byte for each item can make a difference, even with today’s storage allocations. Even when not under tight constraints, all things being equal, we’d like to optimize our performance.

In some cases, though, it’s better not to optimize. I’m not talking about avoiding premature optimization – I’m talking about not optimizing at all. For example, suppose you have an object which will be instantiated a few dozen times (with each instantiation being stored on disk) and there are two ways you can code it. One will require an additional string value, the other will simply perform some calculations (perhaps a dozen lines of code) each time the object is loaded. The time to do this calculation will be unnoticeable. Should the value be included or not?

At first glance we might say, sure, the calculation time is insignificant so we might as well do it. On the other hand, since the object will only be instantiated a few times, the extra space requirements are also insignificant; it simply makes no difference to the performance whether we store the extra item or not.

Does that mean it doesn’t matter which decision we make? In this case….no. We also have to factor in the complexity of the calculation: not to the computer, but to the programmer. Adding extra code makes it that much more likely that a bug will slip in someplace; given two options where neither has a performance benefit, we should opt for the simpler one. In this case, then, I would choose to use the extra item, not to save the calculation time for the computer, but to save the mental energy of the programmer by making the code that much simpler.

The importance of downtime

As I write this, it’s the day before I return to work after a sabbatical. I’ve spent the last two weeks in Europe, exploring castles in England and munching crepes and escargot in France. What I have not done is anything related to work.

Cat relaxing
By Kreuzschnabel (own work) via Wikimedia Commons

In fact, before I left home I did two things. I removed the sim card from my phone (I got a temporary one in Europe to provide a data plan there) and I shut off my work email, so I wouldn’t get any emails from work even when connected to wifi. In my last team meeting before I left, I made it clear that I would be unreachable while I was gone.

Over the last five years, once thing I’ve noticed is that even when I’m on vacation – whether I’m visiting my family in Colorado or an art museum in Chicago – I still end up answering work emails, which means some of my attention is still on work. It might not take that much time to respond to a few emails, but how much can you relax when you’re still thinking about the job?

Tomorrow, I’ll have many emails to respond to. Tomorrow, people will need my input on many things, and I’ll be busy all day. Today? When I finish this blog post, I’ll be diving into a pluralsight course, without worrying about what I need to do tomorrow. Today, I’ve freed my mind from work for two weeks, and I am relaxed.

 

First thoughts on the Apple Watch

The last time I bought a new watch was probably 2008 or 2009. It was a self-winding mechanical watch with exposed gears that was absolutely beautiful; unfortunately it stopped keeping time in 2010. I received another watch that Christmas, which I wore for a few months, but after that I stopped; after all, why wear a watch when we’re constantly surrounded by clocks? So I’ve been watchless for five years.

One thing I’ve considered for a few years now is a smartwatch, but they haven’t seemed to have enough capability to be worth the money. After reading John Sonmez’s review of the Apple Watch, however, it seemed like it might be worth the investment (particularly when it’s on sale) and my wife picked one up for my birthday present this year. I’ve now been wearing it for about five days, and thought I’d put down my first impressions.

Apple watch - stock image
The Apple Watch – Sport in Space Gray

First things first: I chose the black (Apple calls it Space Gray) 42mm sport watch. This is the second least expensive one (the 38mm sport watch is $50 cheaper); Apple just cut the price to $349 from $399 (along with introducing a number of new bands), but it goes on sale for $299 fairly regularly. The watches all have the same functionality, but depending on which case and band you want, you can spend up to $17,000.

The watch band is a bit odd, but I got used to it pretty quickly. It’s not easy to describe, but it seems to work. Charging is simple – just put the watch on the magnetic inductive charging station and you’re good to go – and pretty quick – I’ve mostly been charging the watch for about an hour a day.

Why get a smartwatch?

Ok, enough of the basics – why am I willing to spend hundreds of dollars on a fancy watch that needs to be charged regularly?

There are, so far as I’ve seen, no “gee-whiz”, astounding apps that make the watch a must have. What it does have is a lot of little conveniences that make your life that much easier. For me, most of them break down into two categories: work and travel.

Work

Like probably most of the people reading this blog, I use a smartphone (obviously, an iPhone) and I get a lot of notifications. At work I’d started leaving my phone on my desk to that I can see why it’s vibrating rather than pulling it out of my pocket; if someone’s calling me, I try to Google the number quickly on the off-chance that it’s someone I’d want to talk to (it almost never is – most of these searches show it’s a scammer calling). Now I leave my phone in my pocket and take a quick look at my watch to see if it’s anything I need to deal with. When I’m out of my office, meeting details come up on my watch so that, again, I don’t have to pull out my phone to see where I’m supposed to be next. It’s not a big deal – is taking your phone out of your pocket really all that difficult? – but it removes a minor irritation.

Commuting

A year ago, I took up listening to audiobooks on my commute; unfortunately, sometimes I miss something, and even if I’m stopped at a light I can’t really pull my phone out and rewind. Now I have the Audible app, so I can just hit the rewind button without taking my eyes off the road. That’s useful.

Travel

Ok, how about non-commuting travel, to new cities? This was actually my justification for getting the watch, as I travel within the US for business and will be visiting London and Paris next month. This past weekend, I tried out the watch features on a trip to Chicago.

When I’m driving someplace unfamiliar, I always use my phone for directions, but I don’t always hear the street name (actually, I usually don’t). Now I can just glance at my watch to see what the next street is and how long until I need to turn; it also vibrates when I reach the turn. This isn’t perfect – the watch is sometimes a bit slow to update after a turn and this seems to drain the battery – but it’s pretty helpful.

The same functionality also works with walking; you can be walking around the city and get your directions without having to take your phone out (and become a target for pickpockets). I used this when walking a few places in Chicago, and I’m looking forward to using it again when riding the tube in London.

I mentioned battery life – aside from the drive to Chicago, I don’t seem to go through battery that quickly. The last few days I’ve slept with my watch on and used the alarm to wake up, then charged the watch for an hour before leaving for work. So far, so good. Since I’m completely deaf when I’m not wearing the processor for my cochlear implant I normally have to carry a vibrating alarm clock when I travel; as you might imagine, this both takes up space and slows down getting through airport security. If the watch keeps waking me up successfully, I’ll no longer need to carry a clock when I travel; I’ll just have to make sure the watch is sufficiently charged before I go to bed!

Other

One thing I should mention that’s pretty cool: in order to save battery, the display is only on when you’re “looking” at it – by which I mean, you have your arm rotated such that the watch face is where you can see it. This isn’t perfect – I have to occasionally wake it up – but it works pretty well and it’s a cool feature.

Something I haven’t tried yet is Apple Pay on the watch – I’ve barely used it on my phone, even – but not having to take my wallet out seems like a good thing. We’ll see how that works out.

Overall impressions

I don’t love everything about the watch; for example, I still haven’t managed to get Siri to work (it activates, but then doesn’t seem to process that I’m talking). Even with the price cut, it’s still pretty expensive. I was used to winding my mechanical watch each day in case it didn’t self-wind enough, so the need to charge the watch isn’t a big deal to me, but it’s still something else to remember.

Are smartwatches, at this point, still overpriced toys? Yes, they are. Do you need to run out and buy one? No, not at all. But if you have a smartphone that supports it (iPhone 5 or later), it’s a pretty nifty gadget that removes a few of the little annoyances of day-to-day life.

I’d buy it again.

Test-driving a Tesla

The inside of the Model S
Testing the Tesla on the streets of Chicago

This past week, I had the opportunity to test-drive a Tesla.

Tesla has been on my radar for a few years now. I’m not much of a car person, but their cars are just really cool and I’ve been considering preordering the model 3, so I took advantage of a trip to Chicago to check out the S.

Overall, there were a few things that I didn’t like about the car. It’s pretty low and isn’t as easy to get into and out of as it could be (and it doesn’t feel as roomy as my Camry). There are no grab bars, but that can be fixed with aftermarket add-ons. The windows are narrower than I like, which cuts down on visibility – but the large screen showing what’s happening around you more or less makes up for that. Overall, the car feels comfortable enough, though not like anything particularly special.

The driving, though, is something else. The handling on this car is pretty solid, and I liked how quiet it is. Chicago traffic meant I never got it up above 35, but I’d love to see how it handles curves at freeway speeds. What little acceleration I was able to do was pretty smooth. I liked the regenerative braking, and I can definitely see why some people make a game out of never using the brakes.

The most interesting thing was probably the autopilot. I engaged it while sitting on the freeway on-ramp and the car immediately accelerated at the car in front of me, only to stop again seconds later – that was a little disconcerting! When that car tried to change lanes a few minutes later, without us having gotten up enough speed for the S to navigate off the lines instead, I had to retake control to keep us from changing lanes as well. The warning beep made it very clear that my attention was needed.

As I said, I’ve never been a car person, and I’ve definitely never considered spending good money on a luxury car. The point of the test drive was to see what Tesla’s work felt like so I could decide whether I’d like the model 3, which comes in at a much more reasonable $35k (before the $7500 tax credit).

But the more expensive versions sure seem awfully appealing…

Delegation, flexibility, and software development

Something that occurred to me yesterday is how much less structured my work week is than it used to be.

When I was a new developer, my TL (team lead) liked to have everyone maintain a spreadsheet showing everything that we were currently working on, with an estimate of how many hours we were planning to put into each item for the coming week. I was never convinced of the ability of the average developer (or, more specifically, of myself) to accurately estimate how long things would take, but it at least showed how much time would be taken up by meetings, vacation, etc, and how much work everyone had on their plate.

Over time, I stopped doing the spreadsheet, and my workplan meetings largely became me saying “I’m currently working on this, this, and this” and my TL saying “ok, sounds good” or “I need you to prioritize this other thing.” This worked for me – I still had a good idea of what I was going to be working on, but I wasn’t spending time typing up estimates of how long each change would take.

These days, that’s still how my workplan meetings go, but two things have changed. One is that I now bring written notes, because even though I don’t feel the need to do the formal plans we used to use, I have too many things going on to remember everything I want to talk about without them. The other is that my plans for the week are much more open-ended: rather than having six fixes I plan to do, I’ll have two or three things at the top of my priority list and other stuff hanging around for “when I get to it.”

Largely, this is because I’ve taken on more responsibility: a lot of my time goes to either dealing with important issues that come in and get routed to me that I wouldn’t know about in advance, or helping newer members of the team. As a result, it’s not unusual that only a minority of my time is actually devoted to what I’d planned to spend the week working on. The other reason is just that I tend to work on larger projects now, which take several weeks or longer to complete, with smaller development thrown in when I need a break; this means it’s rare that I have a half-dozen fixes on my “will absolutely do this week” list.

At the same time, while I’m not directly responsible for any other people on the team, I am in charge of a project that several people are working on, which means I’m setting priorities and making decisions for multiple developers. My impulse so far has pretty much been to pretty much say “here are the team standards and the company standards; I expect you to follow these. Otherwise, work how you like and let me know when you need more.” If I can agree on a design with one of my developers and then not hear from him again until he’s finished coding three weeks later, I’m fine with that; I have no interest in knowing how many hours he’s spending on a given part of his activity each week.

My own feeling is that if you give someone work to do and let them figure out how to get it done (assuming that person is reasonably competent and professional), with the occasional check-in, work will get done more effectively and people will be happier than if you try to micro-manage what’s being done when. At least, that’s always been my experience – if I have multiple things I need to get done, I’ll be more productive if I can just choose to work on whichever item I happen to most feel like working on at the time, not what the schedule says I should be doing. The nice thing about being a software developer is that this is quite possible; as long as I’m hitting my deadlines, how I’m managing my time doesn’t need to concern anyone else.

But it’s still a good thing the computer keeps track of everything I need to do without my having to do anything. My memory isn’t that good…

Checklists and Software Development

In 2011, Atul Gawande published The Checklist Manifesto: How to Get Things Right. I first became aware of it when I had the opportunity to hear him speak during his book tour for his latest book, Being Mortal, at the end of 2014, but only got around to reading it this week. The book is about managing complexity in the medical field, but can also be applied to software development.

Checklist Manifesto book coverThe central thesis of the book is that modern knowledge has made the world too complex for humans to handle unaided. Take any complex profession – medicine, architecture, etc – and you find specialization and sub-specialization: there’s simply too much expertise required for anyone to be a generalist. Even within the sub-specialties, there’s so much to keep track of that it’s easy to miss a step, and that one missed step can result in a collapsed building, crashed airplane, or dead patient. We have finally advanced enough that “errors of ignorance” – mistakes because of what we don’t know – are often less important than “errors of ineptitude” – mistakes from not making proper use of what we know.

The solution is the simple checklist: a written list of the steps to take each time an action (whether it’s landing a plane or checking a patient) is performed. Interestingly enough, the checklists aren’t useful only for those who are new to an area, but even for experts with many years of training and experience who may nonetheless overlook a minor, routine step under stress.

So how can we apply this to software development? I personally use a checklist (in the form of a spreadsheet) that I compare against every new activity my team creates. The list contains around a hundred items to check, from making sure that CSS files are linked in the correct order to ensuring that our naming conventions are followed and strings are properly internationalized. It’s a lot of minor details, the vast majority of which we can expect to do correctly on any given day without the aid of the checklist, but I find that I usually catch a few things in each new activity. Unlike the steps on a doctor’s checklist, these aren’t going to kill anybody if they’re missed – most of them will simply result in a slight inconvenience to us (the developers) in the future – but running through the checklist before the end users ever see the software lets us fix the issues more easily and makes the software look more polished to end users (and testers) as we find issues before anyone sees the results.

Of course, we can also look at non-technical checklists: does the code do what it’s supposed to do, regardless of the implementation? To some extent this is what we’re doing when we write unit tests: we define what each unit should do, and then check that it actually does what we expect. I find that one of the best ways to avoid getting a lot of change requests is to have a checklist of exactly how the finished activity should work, and verify that it meets every one of the requirements (many of which might be too simple to remember when coding) before marking the development as complete.

What processes do you use for finding bugs in code? Can they become a checklist?