My AT&T Uverse Installation Experience

I moved to a new apartment last weekend, and as part of the move I switched from Time Warner cable/internet/phone to AT&T Uverse service.  I made the change because AT&T advertised higher download speeds for a similar price, and my TW connection gave me troubles with Netflix and sometimes Youtube.

With respect to the cable and internet installation I have to say AT&T was stellar.  I had a few issues with my Time Warner installation and none of them were present in this.  My download speeds are within 10% of the advertised speed, and I’m enjoying my service greatly.

The phone installation was a nightmare.  I tried unsuccessfully for two weeks to transfer my number, then had to give up and try unsuccessfully to have AT&T assign me a new number.  Here’s how it worked.

In the 2nd week of August, I called Time Warner and notified them I’d be terminating my service on August 23rd.  They offered me a lower rate, but I really wanted to try Uverse so I continued to cancel.  On the same day, I set up my Uverse service online, and the site told me my number could be ported.  Great!

About a week later, AT&T called me to tell me there was a problem porting the number; apparently the number had a pending order.  I called Time Warner, and the only pending order was the cancellation.  We decided to remove the cancellation order since I could cancel when I turned in my equipment.  I called AT&T and asked them to try again.  I still had about 4 days before moving, so I figured it would be fine.

Nope.  AT&T sent me a few emails the day before the move to indicate there was a problem.  They were trying to port my cell phone number, which had nothing to do with the number I asked them to port.  So I asked them to try again, with the right number this time.

No dice.  AT&T called me the day of my move to let me know there was still a pending order on the number.  Time Warner insisted there were no pending orders.  I couldn’t do anything because I was busy moving, so I put it off until the next day; I still had 2 days until the installation.  I told AT&T to assign me a new number, and after a few minutes the person on the phone told me what my new number would be and I happily continued to wrap up my move.

The day the tech was scheduled to do the installation, I got a call from AT&T.  The robovoice let me know there was a problem porting my number (!) and I’d have to reschedule the voice installation.  What?  I talked to a representative and there was apparently no indication that I’d already been assigned a number.  I asked her to assign me one, and she got confused and decided to remove my voice order.  At this point, the installation tech was at the door so I told her whatever and ended the call.

The installation tech had the number I’d been told I’d be receiving before, and knew nothing of the number port.  We decided to try the voice install and see what happened.  Interestingly enough, the phone halfway worked.  I could dial out, and caller ID would show my old Time Warner number.  But any attempt to dial in failed.  The tech couldn’t really do anything, but told me some stuff to tell the phone support so they wouldn’t waste time sending another technician to “install” the phone kit.  So I ate lunch and started that call.

It was an hour-long ordeal.  The first tech support guy couldn’t really do anything because the woman earlier in the morning had removed voice service from my account.  He transferred me to someone in sales. She added voice service again, and helped me notice that I’d lost the promotional credits to my account in all of this and re-applied them. After doing that, all she could do was schedule a voice installation, but when I explained that I was already installed and just needed a number she went to talk to some supervisors and figured out she could connect me to someone in high-level tech support. This guy was very confused that I was calling him from a cell phone; apparently he thought I was calling him from my voice service that I had already explained I didn’t have.  After I explained (twice) that neither my cell phone number nor the Time Warner number should be ported and I needed a brand new number, he got to work.  Some 20 minutes later, he told me I had a number and read it to me.  We did a test call, it worked, everything’s happy.

The number he read to me isn’t the phone number I have.  It was a kind of final problem, but it wasn’t tough to call my cell phone to figure out what my real number was.

What the heck happened?  How could AT&T screw up phone service this bad, isn’t it their traditional business?  Why did they give up on trying to transfer my Time Warner number and start trying other numbers associated with my account?  Why didn’t tech support on Tuesday know what tech support on Monday had done?  How did my installer get “Give this man number A” without my account having a note of that?  Why couldn’t the final and helpful person read me the number he *actually* assigned to me?

Aside from that, I’d highly recommend Uverse, I just had to vent about the phone process.

Is parameterized logic always harmful?

I’ve read plenty of times that parameterized logic is considered harmful in testable design.  What’s parameterized logic?  It’s stuff like this:

int Calculate(int lhs, int rhs, Operation op)
{
    if (Operation == Operation.Add)
    {
        return lhs + rhs;
    }
    else if (Operation == Operation.Subtract)
    ...
}

From what I understand, testable design would say this method needs to be refactored.  It does multiple things, and the op parameter dictates what happens.   The reason it’s discouraged is you end up encoding contract for *all* of the operations.  For example, if there is an Operation.Divide then the method will throw an exception if rhs is 0.  Testing this method is possible, but will be tedious.  Documenting this method will be a pain as well.

One alternative would be to replace the single Calculate() method with individual methods like Add(), Subtract(), and so on.  Another technique would involve creating an interface for a type that can operate on two numbers and letting Calculate() take one of those:

int Calculate(int lhs, int rhs, Operator op)
{
    return op.Operate(lhs, rhs);
}

Obviously the injection technique is more complicated, but it provides flexibility: in a library it allows the ability for users to provide their own implementations of Operator that perform operations that might not be built in.  Calculate() still has multiple behaviors, but the testing and documentation burden is shifted to the Operation implementations.

So what got me thinking about this?  Someone asked me how to convert to and from hexadecimal strings in .NET.  I realized there’s three ways to do it: Parse(), TryParse(), and Convert class methods.  I don’t like the thought of convincing someone there’s “one true way” to do things, so I outlined all three and noticed that all three techniques use parameterized logic.

The Parse() and TryParse() techniques will parse a number differently depending on the NumberStyles parameter you pass.  For example, “10” will parse as 10 unless NumberStyles.HexNumber is specified; then it will parse as 16.  Likewise, “B000” is a valid input only when the hex number style is specified.  From a testability standpoint, this seems like it’d require a matrix of tests for just the method.  From a documentation standpoint, Microsoft just documents that a FormatException can be thrown without going into any detail (granted, it’s usually easy to figure out why the exception was thrown.)

I feel like Convert’s methods do things differently.  The relevant methods take the string and an integer that represents the base for conversion.  This still introduces the problem that sometimes 10 means 16 and sometimes “A” is invalid.

So what’s different between the two?  From a user’s standpoint, not much.  If you try to guess the implementation, I bet they’re very different.  Byte.Parse() probably looks like this:

static byte Parse(string input, NumberStyles numberStyles)
{
    if (IsSet(numberStyles, numberStyles.HexNumber))
    {
        // parse hexadecimal
    }
    else
    {
        // parse decimal
    }

    // validate the number using the various other styles
}

Convert.ToByte() could probably look like this:

static byte ToByte(string input, int base)
{
    // some algorithm that parses a number with an arbitrary base
}

I could use Reflector and peek at them, but I’m only using these as examples of the implementation styles I’m interested in (and yes, I know ToByte() only accepts 3 bases.)  I feel like ToByte() here is the lesser of two evils because of the internals.  Parse() has rigid rules that require you to walk through each possible path of the code if you want to create a 100% coverage of the logic.  ToByte() implements an algorithm that should work for many values of base, and thus you can write a smaller number of tests to get full logic coverage.

So I feel like depending on how you implement the parameterized logic, you might reduce the testing and documentation burden.  The Parse() implementation requires a suite of tests for every base and many combinations of the NumberStyles parameter.  The ToByte() implementation requires a suite of tests against an algorithm that takes a parameter.  It feels like that ought to reduce the number of tests; I can imagine using Xunit .NET’s theory tests to dramatically reduce the testing effort.

But I don’t think it’s so straightforward as, “Don’t use parameterized logic unless the parameter is an input to an algorithm.”  Consider what the interface for parsing numeric strings would look like if parameterized logic weren’t available:

structure Int32
{
    // ...

    static Int32 ParseHexNumber(...);
    static Int32 ParseHexNumberAllowWhitespace(...);
    static Int32 ParseHexNumberAllowLeadingWhitespace(...);
    static Int32 ParseHexNumberAllowTrailingWhitespace(...);
    static Int32 ParseHexNumberAllowWhitespace(...);
    ...
}

What a mess! I would not call this an improvement, even if it meant the testing/documentation were more clear.  So it looks like parameterized logic is yet another place where the developer must balance ease of use vs. maintainability.  While the pattern used in my Parse() implementation above is definitely a testing and maintenance nightmare, it is not acceptable to force the user to experience pain.