Wednesday, June 6, 2018

Sponsor Post: Six Months of Free Monitoring at Panopta for TDWTF Readers

You may not have noticed, but in the footer of the site, there is a little banner that says:

Monitored by Panopta

Actually, The Daily WTF has been monitored with Panopta for nearly ten years. I've also been using it to monitor Inedo's important public and on-prem servers, and email and text us when there are issues.

I started using Panopta because it's easy to use and allows you to monitor using a number of different methods (public probes, private probes and server agents). I may install agents for more detailed monitoring going forward, but having Panopta probe HTTP, HTTPS, VPN, and SMTP is sufficient for our needs at the moment. We send custom HTTP payloads to mimic our actual use cases, especially with our registration APIs.

If you're not using a monitoring / alerting platform or want to try something new, now's the time to start!

Panopta is offering The Daily WTF readers six months of free monitoring!

Give it a shot. You may find yourself coming to dread those server outage emails and SMS messages. PROTIP: configure the alerting workflow to send outage notices to someone else to worry about.

Disclaimer: while Panopta is not paid sponsor, they been generously providing free monitoring for The Daily WTF (and Inedo) because they're fans of the site; I thought it was high time to tell you about them!

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!


To read the full article, please visit The Daily WTF

CodeSOD: Many Happy Returns

We've all encountered a situation where changing requirements caused some function that had a single native return type to need to return a second value. One possible solution is to put the two return values in some wrapper class as follows:

  class ReturnValues {
    private int    numDays;
    private String lastName;

    public ReturnValues(int i, String s) {
      numDays  = i;
      lastName = s;
    }

    public int    getNumDays()  { return numDays;  }
    public String getLastname() { return lastName; }
  }

It is trivial to add additional return values to this mechanism. If this is used as the return value to an interface function and you don't have access to change the ReturnValues object itself, you can simply subclass the ReturnValues wrapper to include additional fields as needed and return the base class reference.

Then you see something like this spread out over a codebase and wonder if maybe they should have been just a little less agile and that perhaps a tad more planning was required:

  class AlsoReturnTransactionDate extends ReturnValues {
    private Date txnDate;
    public AlsoReturnTransactionDate(int i, String s, Date td) {
      super(i,s);
      txnDate = td;
    }
    public Date getTransactionDate() { return txnDate; }
  }
  
  class AddPriceToReturn extends AlsoReturnTransactionDate {
    private BigDecimal price;
    public AddPriceToReturn(int i, String s, Date td, BigDecimal px) {
      super(i,s,td);
      price = px;
    }
    public BigDecimal getPrice() { return price; }
  }

  class IncludeTransactionData extends AddPriceToReturn {
    private Transaction txn;
    public IncludeTransactionData(int i, String s, Date td, BigDecimal px, Transaction t) {
      super(i,s,td,px);
      txn = t;
    }
    public Transaction getTransaction() { return txn; }
  }

  class IncludeParentTransactionId extends IncludeTransactionData {
    private long id;
    public IncludeParentTransactionId(int i, String s, Date td, BigDecimal px, Transaction t, long id) {
      super(i,s,td,px,t);
      this.id = id;
    }
    public long getParentTransactionId() { return id; }
  }

  class ReturnWithRelatedData extends IncludeParentTransactionId {
    private RelatedData rd;
    public ReturnWithRelatedData(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd) {
      super(i,s,td,px,t,id);
      this.rd = rd;
    }
    public RelatedData getRelatedData() { return rd; }
  }

  class ReturnWithCalculatedFees extends ReturnWithRelatedData {
    private BigDecimal calcedFees;
    public ReturnWithCalculatedFees(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf) {
      super(i,s,td,px,t,id,rd);
      calcedFees = cf;
    }
    public BigDecimal getCalculatedFees() { return calcedFees; }
  }

  class ReturnWithExpiresDate extends ReturnWithCalculatedFees {
    private Date expiresDate;
    public ReturnWithExpiresDate(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed) {
      super(i,s,td,px,t,id,rd,cf);
      expiresDate = ed;
    }
    public Date getExpiresDate() { return expiresDate; }
  }

  class ReturnWithRegulatoryQuantities extends ReturnWithExpiresDate {
    private RegulatoryQuantities regQty;
    public ReturnWithRegulatoryQuantities(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed, RegulatoryQuantities rq) {
      super(i,s,td,px,t,id,rd,cf,ed);
      regQty = rq;
    }
    public RegulatoryQuantities getRegulatoryQuantities() { return regQty; }
  }

  class ReturnWithPriorities extends ReturnWithRegulatoryQuantities {
    private Map<String,Double> priorities;
    public ReturnWithPriorities(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed, RegulatoryQuantities rq, Map<String,Double> p) {
      super(i,s,td,px,t,id,rd,cf,ed,rq);
      priorities = p;
    }
    public Map<String,Double> getPriorities() { return priorities; }
  }

  class ReturnWithRegulatoryValues extends ReturnWithPriorities {
    private Map<String,Double> regVals;
    public ReturnWithRegulatoryValues(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed, RegulatoryQuantities rq, Map<String,Double> p, Map<String,Double> rv) {
        super(i,s,td,px,t,id,rd,cf,ed,rq,p);
        regVals = rv;
    }
    public Map<String,Double> getRegulatoryValues() { return regVals; }
  }

The icing on the cake is that everywhere the added values are used, the base return type has to be cast to at least the level that contains the needed field.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!


To read the full article, please visit The Daily WTF

Tuesday, June 5, 2018

Representative Line: A Test Configuration

Tyler Zale's organization is a automation success story of configuration-as-code. Any infrastructure change is scripted, those scripts are tested, and deployments happen at the push of a button.

They'd been running so smoothly that Tyler was shocked when his latest automated pull request for changes to their HAProxy load balancer config triggered a stack of errors long enough to circle the moon and back.

The offending line in the test:

assert File(check_lbconfig).exists and File(check_lbconfig).size == 2884

check_lbconfig points to their load balancer config. Their test asserts that the file exists… and that it's exactly 2884 bytes long. Which, of course, raises its own question: if this worked for years, how on Earth was the file size never changing? I'll let Tyler explain:

To make matters worse, the file being checked is one of the test files, not the actual haproxy config being changed.

As it turns out, at least when it comes to the load balancer, they've never actually tested the live cofig script. In fact, Tyler is the one who broke their tests by actually changing the test config file and making his own assertions about what it should do.

It was a lot more changes before the tests actually became useful.

[Advertisement] Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.


To read the full article, please visit The Daily WTF

Monday, June 4, 2018

CodeSOD: A/F Testing

A/B testing is a strange beast, to me. I understand the motivations, but to me, it smacks of "I don't know what the requirements should be, so I'll just randomly show users different versions of my software until something 'sticks'". Still, it's a standard practice in modern UI design.

What isn't standard is this little blob of code sent to us anonymously. It was found in a bit of code responsible for A/B testing.

    var getModalGreen = function() {
      d = Math.random() * 100;
      if ((d -= 99.5) < 0) return 1;
      return 2;
    };

You might suspect that this code controls the color of a modal dialog on the page. You'd be wrong. It controls which state of the A/B test this run should use, which has nothing to do with the color green or modal dialogs. Perhaps it started that way, but it isn't used that way. Documentation in code can quickly become outdated as the code changes, and this apparently extends to self documenting code.

The key logic of this is that 0.5% of the time, we want to go down the 1 path. You or I might do a check like Math.random() < 0.005. Perhaps, for "clarity" we might multiply the values by 100, maybe. What we wouldn't do is subtract 99.5. What we definitely wouldn't do is subtract using the assignment operator.

You'll note that d isn't declared with a var or let keyword. JavaScript doesn't particularly care, but it does mean that if the containing scope declared a d variable, this would be touching that variable.

In fact, there did just so happen to be a global variable d, and many functions dropped values there, for no reason.

This A/B test gets a solid D-.

[Advertisement] Forget logs. Next time you're struggling to replicate error, crash and performance issues in your apps - Think Raygun! Installs in minutes. Learn more.


To read the full article, please visit The Daily WTF

Friday, June 1, 2018

Error'd: I Beg Your Entschuldigung?

"Delta does not seem to be so sure of what language to address me in," writes Pat.

 

"I'm wondering if the person writing the release notes made that typo when their mind was...ahem...somewhere else?" writes Pieter V.

 

Brad W. wrote, "For having "Caterpillar," "Revolver," and "Steel Toe" in the description the shoe seems a bit wimpy...maybe the wearer is expected to have an actual steel toe?"

 

"Tomato...tomahto...potato...potahto...GDPR...GPRD...all the same thing. Right?" writes Paul K.

 

"Apparently installing Ubuntu 18.04 on your laptop comes with free increase of battery capacity by almost 40x! Now that's what I call FREE software!" Jordan D. wrote.

 

Ian O. writes, "I don't know why Putin cares about the NE-2 Democratic primary, but I'm sure he added those eight extra precincts for a good reason."

 

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!


To read the full article, please visit The Daily WTF