Getting Vim to stop indenting C++ namespace blocks.

January 19th, 2009

I searched around quit a bit when trying to solve this one and didn’t ever come across a solution. I ended up coding one up and thought I might as well post it in case someone else comes across the same need. I needed Vim’s cindent to do the following:

namespace foo {

typedef struct _Bo {
    int a;
    int b;
} Bo;

class Bar {
public:
    Bar();
    virtual ~Bar();
...
}

void baz() {
}

}

The thing of note here is the namespace block doesn’t doesn’t cause an indent shift. Everything inside is backed up against column 0. There’s no quick and easy cinoption for it so far as I could tell or find and I was able to get all of the other formatting options to match our needs. I did find indentexpr and was able to code up something that gets the desired behavior, it is as follows:

function FixCppNamespaceIndent(lnum)
    " cursor set to lnum
    call cursor(a:lnum, 1)
    " search backwards for opening {
    let p = searchpair('{', '', '}', 'bW')
    if p > 0
        " we're in a { }
        let pl = getline(p)
        " get the line with the opening of our block
        if pl =~ 'namespace'
            " it contains the word namespace so we're shifted 0
            return 0
        else
            " doesn't contain the word namespace so we're normal
            return cindent(a:lnum)
        end
    endif
endfunction

set indentexpr=FixCppNamespaceIndent(v:ln

Won’t guarantee there aren’t a few bugs in cases I haven’t yet run across, but I haven’t seen any problems out of it. One thing I’m not sure about is what will happen with nested namespace, I guess it will depend on what the desired behavior is. Anyway, I’ll solve that if and when I come across it.

Worse is Better

September 7th, 2007

Worse is better Definitely heard the expression before, even roughly knew what was meant by it, but it goes along with my previous post really well.

Buy a shirt, I hear they’re the new hotness.

make custom gifts at Zazzle

legacy – now with less bitching

August 5th, 2007

so as mentioned in the previous post i don’t have answers, but all i did then was bitch and whine. surely i can do better than that so i’m returning to the subject after talking a bit about it w/matt, which lead me to think more on the subject. i still don’t have answers, but now i will at least offer succinct thoughts.

reasons for action

  • the code it’s core/central to your biz and agility is necessary – if it’s not then why are you thinking about it
  • scaling is important – partitioning/sharding or just general efficiency – simple and clean scales
  • things are fragile and unstable, a lot of development time is lost to debugging, changing something small in one place breaks things elsewhere
  • to avoid the broken window principle – read the pragmatic programmer already
  • looking at the code is painful, working with it hurts, you don’t want to get out of bed (weekday) mornings

reasons for complacency

  • you don’t know what needs to be done to improve it – what “better” would look like
  • can’t afford the initial cost (loss in forward progress) – you’ll lose 10 times it in the long run tho so be ware.
  • new bugs or reappearance of previously solved problems – less likely if people have been around the code for a while and were involved with building it the first time around

ways to go about it

  • start from scratch – build a new system using what you can, but starting with as little as possible of the existing.
    • advantages
      • biggest improvements, revolutionary
      • less overall effort required to get there
      • easier, requires less experience, skill, knowledge, and care. you just have to know where you’re going, not an incremental path there
    • disadvantages
      • initial hit, you don’t see immediate results of the effort
  • refactor – pick a piece and clean it up, rinse and repeat
    • advantages
      • incremental improvements, you can stop at any time, evolutionary
      • no initial hit, you see immediate results, but their small
    • disadvantages
      • way more overall effort required to get there
      • 10x the skill and planning required to get there in one piece
      • constant potential for regressions rather than all at once of redo
      • boundless patience and endurance, yikes
  • stick with it – keep on the current course, add to what you already have but don’t change it
    • advantages
      • none really, unless the piece of code is going to be short lived, remain untouched and effort would be wasted
    • disadvantages
      • life sucks

side note: unit tests, the more thorough the better, are your best friend when it comes to refactoring. at amazon we were able to redo substantial portions of a system, partition it out to multiple databases with disparate schema, to avoiding having to take downtime for lengthy migrations upfront, without any production bugs post change. this was b/c we had an environment where unit testing was easy to build and we built lots of it. do it, the time required with pay off 3 fold. in fact i’m going to return to this subject now that i think about it.

after reading the above it becomes obvious, to me even, that i lean towards action, there are few situations where you won’t benefit from revisiting, refactoring, and improving an existing system. btw, if you happen to have one of them then you probably don’t want to hire me :)

legacy

August 5th, 2007

lexmark was morbidly scared of change. amazon on the other hand couldn’t get enough of it. the mindset at each place was a direct result of overall culture, which i should return to at some point, but for now i want to stick to legacy. what’s good about it, what’s bad, and my current thoughts or lack thereof on how to navigate situations involving large and aging legacy code.

at this point in my career programming isn’t hard, designing and building systems isn’t hard. it takes some time and thought, but it’s not difficult. what is difficult, extremely so for me because i haven’t come up with a way to cope with it, is dealing with legacy systems. i guess i should elaborate b/c it’s more than legacy systems, it’s systems that are complicated, fragile, and stagnate (incapable of agility.) i lose sleep, get depressed, frustrated, exasperated, and just don’t want to touch them. i want to know how to deal with this. in reality i think i just have to quit caring (so much,) but i never seem to be able to do it.

note: when i say legacy i guess i really mean crufty stuff that is a pain to live with, impossible to understand and debug, with that said.

legacy is good because…

it is known, there are probably bugs, but they don’t show up. the bad ones were seen and hopefully corrected long ago. it probably works right now, and in some cases that’s good enough. if it’s not part of your core business function you may not need it to be better. if you don’t deal with lots of request for features and one-off behaviors you may not need to be that agile and might be able to afford a longer dev cycle, but even so who wants things to work that way.

legacy is bad because…

it slows development down. everything takes 3 times longer to do than it should. changing a tiny piece of functionality in one place breaks 4 others and worse yet in subtle ways that are not immediately visible. it’s harder to debug, you can’t tell what’s going on when a system goes wrong. there are two many moving parts. the functions supporting a use case are spread throughout the code and can’t be easily grokked, updated and modified. multiple people can’t work on it without stepping on each other’s toes since pieces are so tightly intertwined. code can’t be reused, every new feature requires changes at every level in the code. the more code in a system the harder it will be to maintain and the longer a system has been around the more code it’s going to have.

it’s not all bad…

legacy is kinda of misnomer, not all legacy is bad legacy (though it seems that way at times.) things can always improve, but the better they are done the less likely it needs or will ever need to be scrapped and redone. if you get nothing else from this essay please take away this: contrary to what people often seem to think it does not take longer to build things right. i can’t tell you how many times i’ve heard it said that it’s this way b/c we were in a hurry and just threw it together. when it’s valid/true it’s partly the broken window principle and the other part building on a shaky foundation. if things were done well from the start it still wouldn’t be taking longer to do things the right way. just as it wouldn’t of taken longer to do things up until this point the right way. the wrong way takes longer, maybe not when extremely short sighted, like days, but anything past that doing things the quick and dirty way always takes longer than the right way, and it’s just as quick. i guess the problem is that you have to know the right way, but …

the right way…

if only there was a right answer. having gone through both lexmark and amazon i can say that amazon was a much more agile and effective environment not to mention pleasant to work in. at the same time you have to be careful, in a small company you can’t always afford to screw up, both amazon and lexmark can. i hear from friends still at lexmark from time to time that they’re slowly starting to come around and see their legacy problem, but still afraid to do what it really takes to address it. so the right way is to do things better/right from the start, but what do you do if it’s not the start and you’ve got negative legacy, hell if i really know. i’d want to ditch it for my own sanity, but that might not always be the best route. maybe i’ll figure it out sometime, if i do you’ll be the first to know.

balancing priorities

June 29th, 2007

there are 4 main things i take in to consideration when designing and coding a (piece of a) system. every decision is an evaluation and maximization of those factors.

  • correctness
  • performance
  • flexibility
  • low-maintenance

correctness

there’s a functional bar above which you must be to ride. if you don’t meet that you’ve made a piece of shit. that much is straightforward, but above that bar is a different story. there’s completely 100% functionally correct and if you’re building the flight controller for the space shuttle or a 777 then you probably need to aim for it. otherwise, you can probably trade off more than you would think. in a system that serves up ads no one is going to die if you serve an ad that is supposed to get 1000 impressions 1001 times. someone might lose a penny and someone else might get a free placement, but that’s not the end of the world. prototypes are another good example and most all startups should really consider themselves in the prototyping stage for a lot longer than you would think. with a prototype it doesn’t matter if you drop a few request every once in a while and the user gets an error or has to try again. people won’t put up with shoddy work, but they will accept a few issues now and then. is it really worth the extra week of time it will take to get your (stealth mode) dog dating google mashup to be completely bug free or would you be better off moving on to new features. data duplication is another good example of a correctness trade off that sometimes has to be made (often in order to scale or span geographic space.) i’ve met a lot of people who were unable to let go of correctness (i call it the phd problem. not because it’s limited to phd’s, but because a majority of them seem to have it.) takeaway: sometimes you need to trade unnecessary correctness for gains in in other areas.

performance

performance just doesn’t matter 90% of the time. if you know how to do it it’s pretty easy and can be achieved cheaply, but if you don’t your in trouble b/c you’ll spend enormous efforts for little gains by optimizing the wrong things. and you probably don’t need to anyway. if performance is a consideration/requirement the key is simplicity. (a concept that i will likely repeat in anything i write and in fact will repeat in the following two categories.) performance starts with the db schema, it just about ends there as well and if it wasn’t for api (in the web service world) it would. i will return to performance and give as much as i can share about i in future posts, but for now i’m going to confine myself to saying that it’s importance id defined completely on the current and short-medium term needs of the system. if you need scale now or will in the next few months take it in to consideration, trade other things for it. if you need scale in six months then start to think about it and plan for it, but don’t build it, just know how you’re going to. if you think you need to scale at a point further out than that then don’t bother, give away performance in trade for overall simplicity.

flexibility

startups survive on it and it makes life orders of magnitude more bearable. build exactly what you need to do what you’re trying to do today and nothing more, but in a way that you can extend it minimally to do whatever it is you end up needing to do tomorrow. this is hard. don’t implement the functionality you’re sure you’ll need in a couple weeks b/c you will need it, but you won’t know exactly what it will look like and you’ll get it wrong if you do it now. the best advice i can give is to plan for and think about every way you can see the system going, but don’t build any of it. just keep it in mind when you build only what you immediately need. if you get this right the payoff will be getting the new features working in a couple days rather than a few weeks. there’s no magic here, you just have to do it over and over and learn from you mistakes. simple things are easier to extend. minimal/efficent apis allow you more freedom to change around the internals without bothering/changing the clients. using generic structures (maps) in the api or on the database (serialized or secondary table.) so long as you don’t need to search or sort by it things like this will let you add new information to the call and/or db without any changes to the system. producers and consumers of the data need to know about the changes but the intermediate system doesn’t. prevent the system from caring about the details of how it’s used and it won’t have to change when it needs to be used in a new way.

low-maintenance

low maintenance starts with flexibility, but it doesn’t end there. the more complex your solution the more that can and will go wrong with it. when presented with the choice of a system that monitors itself, brings nodes in and out of the cluster, and gets them up to speed and a dirt simple caching system like memcached go with simple. chances are that it will go down less often than the complex system gets in to broken states that it can’t self recover from. this isn’t just limited to solutions you pick, it also applies to stuff you build. the more complicated it is, the more moving parts the more it will go wrong. it might be built to handle all of the failure modes, but it won’t happen, period. let things fail, work around the failures or better yet don’t care about them. the best solutions simply relies on redundant components. at most they fail over to a hot/cold standby, nothing more complicated than that. the situations where the complexity is preferable are few and far between. if your service doesn’t care about how it’s used you won’t have to change it when you get that new use case that needs to be implemented by the end of the week. the code changes you need to make might only take you a couple hours to do, but if you add in the changes required to clients, which may also need to be done for unrelated systems it ads up. on top of that the release, build, and test processes as well as the coordination required to do a synchronized push of several dependent pieces will quickly eat up time and turn what should be a couple days work for a new feature in to a week or so, …

finding the optimal relative importance of the four factors and thus making the correct design decisions is a black art, one that i have worked on mastering, but will never complete. it’s the type of thing that i look back at what i did yesterday and can’t stand it, would do it differently now that i’ve learned more… while i’ve talked about the 4 pieces in the context of systems they apply at all levels and in fact building good solutions requires thinking in these terms at every level. i’ll hopefully come back and revisit these priorities in the near future in other settings. if you have questions ask away.