Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
pseudorandom name
May 6, 2007

According to ISO 8601, a "week numbering year" has 52 or 53 weeks (364 or 371 days). Weeks start on Mondays and the first week of the year is the week containing the first Thursday of the year.

The %G and %g formats to strftime() use the ISO 8601 week numbering year instead of the actual year as used by %Y and %y.

Now you know why Twitter stopped working 6 hours ago.

Adbot
ADBOT LOVES YOU

omeg
Sep 3, 2012

Everything that has to do with time is evil.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

pseudorandom name posted:

According to ISO 8601, a "week numbering year" has 52 or 53 weeks (364 or 371 days). Weeks start on Mondays and the first week of the year is the week containing the first Thursday of the year.

The %G and %g formats to strftime() use the ISO 8601 week numbering year instead of the actual year as used by %Y and %y.

Now you know why Twitter stopped working 6 hours ago.

I don't, actually. Why did Twitter go down?

Jewel
May 2, 2009

Suspicious Dish posted:

I don't, actually. Why did Twitter go down?

OAUTH said "hey your tokens are expired it's dec 2015" but kept handing out normal 2014 tokens so nobody on a lot of clients could do anything.

No Safe Word
Feb 26, 2005

re: the Twitter stuff

https://twitter.com/_Ninji/status/549365454322802688

Evil_Greven
Feb 20, 2007

Whadda I got to,
whadda I got to do
to wake ya up?

To shake ya up,
to break the structure up!?

pseudorandom name posted:

According to ISO 8601, a "week numbering year" has 52 or 53 weeks (364 or 371 days). Weeks start on Mondays and the first week of the year is the week containing the first Thursday of the year.

The %G and %g formats to strftime() use the ISO 8601 week numbering year instead of the actual year as used by %Y and %y.

Now you know why Twitter stopped working 6 hours ago.
The most beautiful coding horror.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
I mean, it's not like there's any better choice when dealing with times, because we're sincerely hosed, but why does the year start on the first Thursday?

Knyteguy
Jul 6, 2005

YES to love
NO to shirts


Toilet Rascal
C# code:
public WMSManifestTable parmWMSManifestTable(WMSManifestTable _manifestTable = glblManifestTable)
{
    glblManifestTable = _manifestTable;

    return glblManifestTable;
}
Not actually c#.

qntm
Jun 17, 2009
The year (and the week) always start on a Monday, at least by this definition, however:

quote:

The ISO 8601 definition for week 01 is the week with the year's first Thursday in it. Mutually equivalent definitions would be possible based on the following properties of this week:

* It is the first week with a majority (4 or more) of its days in January.
* Its first day is the Monday nearest to 1 January.
* It has 4 January in it. Hence the earliest possible dates are 29 December through 4 January, the latest 4 through 10 January.
* It has the year's first working day in it, if Saturdays, Sundays and 1 January are not working days.

The bolded one is the one I think is most likely to have driven this decision.

itskage
Aug 26, 2003


Knyteguy posted:

C# code:
public WMSManifestTable parmWMSManifestTable(WMSManifestTable _manifestTable = glblManifestTable)
{
    glblManifestTable = _manifestTable;

    return glblManifestTable;
}
Not actually c#.

This is not a horror, this is the X++/MorphX standard set by Microsoft.

Read this: http://sysdictcoder.com/the-x-way-to-getters-and-setters/

You are going to see this a lot in Dynamics AX. I think it's actually pretty clever since you only need to write one method instead of two, though it doesn't really follow conventional philosophies (which could actually be the horror I admit).

When in Rome though...

Also I added this to my Dev instance:
http://sashanazarov.blogspot.com/2012/07/parm-methods-generator-script.html

It's two methods you can add that crawls class declarations and automatically generates these parm methods. I altered mine a bit so it asks me with Box::YesNo if I want to make the method, and to also skip ones where the method already exists.

Pretty handy if you are making a lot of new classes and don't want to do a bunch of typing or copy/pasting.

Knyteguy
Jul 6, 2005

YES to love
NO to shirts


Toilet Rascal

itskage posted:

This is not a horror, this is the X++/MorphX standard set by Microsoft.

Read this: http://sysdictcoder.com/the-x-way-to-getters-and-setters/

You are going to see this a lot in Dynamics AX. I think it's actually pretty clever since you only need to write one method instead of two, though it doesn't really follow conventional philosophies (which could actually be the horror I admit).

When in Rome though...

Also I added this to my Dev instance:
http://sashanazarov.blogspot.com/2012/07/parm-methods-generator-script.html

It's two methods you can add that crawls class declarations and automatically generates these parm methods. I altered mine a bit so it asks me with Box::YesNo if I want to make the method, and to also skip ones where the method already exists.

Pretty handy if you are making a lot of new classes and don't want to do a bunch of typing or copy/pasting.

Hm I see. I agree that's a pretty clever way of implementing accessors. I was thinking of this being used internally in the class's other methods, so it looked extremely unnecessary at first glance. Good info; thanks.

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

omeg posted:

Everything that has to do with time is evil.

My favorite time-related bug is the Zune leap year bug that made a bunch of Zunes not boot up on Dec. 31, 2008. Back when I was still teaching, it was an awesome example to use in intro classes to get the point across that people should test their poo poo, especially special cases, because it's not super advanced – just while loops, if statements, and math.

qntm
Jun 17, 2009
We had a unit test once which only failed on Sundays.

Jewel
May 2, 2009

qntm posted:

We had a unit test once which only failed on Sundays.

Shouldn't a unit test never use anything that changes like "the current time"? How did that even happen?

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Jewel posted:

Shouldn't a unit test never use anything that changes like "the current time"? How did that even happen?

The current date/time represents an external dependency that should be mocked, yes.

Wardende
Apr 27, 2013

Ithaqua posted:

The current date/time represents an external dependency that should be mocked, yes.

So is that just an interface wrapper around System.DateTime or how is that usually accomplished?

pigdog
Apr 23, 2004

by Smythe

Wardende posted:

So is that just an interface wrapper around System.DateTime or how is that usually accomplished?

Pretty much. You don't use System.DateTime directly, but only from your own myOwnCurrentTime() method, which you can mock as needed.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Wardende posted:

So is that just an interface wrapper around System.DateTime or how is that usually accomplished?

In C#, that's one option. Another (which I rather like) is to just pass a Func<DateTime> in the constructor:

code:
public class ThingyThatNeedsADateTime
{
    private Func<DateTime> dateTimeProvider;

    public ThingyThatNeedsADateTime() : this(() => DateTime.Now) { }
    public ThingyThatNeedsADateTime(Func<DateTime> dateTimeProvider) 
    {
        this.dateTimeProvider = dateTimeProvider;
    }
}
Then you can pass in a lambda to be executed when dateTimeProvider is called. That works best for simple cases -- if your method measures the time elapsed between two events, you'll probably be better off wrapping everything up behind an interface and writing a custom provider implementation so you can expose fine-grained control over how it behaves in test scenarios.

qntm
Jun 17, 2009

Jewel posted:

Shouldn't a unit test never use anything that changes like "the current time"? How did that even happen?

I had to go and look this up in our old bug tracker and it turns out the answer is "horrible non-deterministic date parsing behaviour". Heavily edited for clarity, with emphasis added:

quote:

Our software considers a "week" to begin on a Sunday and run through to a Saturday. Each day of the week has a number: Sunday = 1, Monday = 2, Tuesday = 3, Wednesday = 4, Thursday = 5, Friday = 6, Saturday = 7.

January 1 is always considered to fall in week 1 of that year. Since a year is 52 weeks and 1 day (2 days in a leap year), a calendar year can span up to 54 weeks.

In this test we parse the strings "0-54" and "00-54" as dates, using the date format strings "Y-ww" and "YY-ww" respectively. Here, "ww" represents WEEKINYEAR, namely a week number with a leading zero. "0-54" and "00-54" both mean "Year 2000, week 54". When parsing a string like "0-54" or "00-54" as a date, no day number is given, so the system uses the current day number. On a Sunday, "0-54" and "00-54" are parsed as Sunday 31 December 2000. On Monday through to Saturday, "0-54" and "00-54" are parsed as dates from Monday 1 January 2001 to Saturday 6 January 2001.

The problem comes when we take the resulting date and format it back out as a string using the "Y-ww" or "YY-ww" format again.

Expected behaviour (according to the test as written): On Sunday, the result should be "0-54" or "00-54" again. On Monday through to Saturday, the result should be "1-01" or "01-01" respectively.

Actual behaviour: The returned value is "1-01" or "01-01" regardless of the day on which the test is run. On Monday through to Saturday, this is the correct result, but on Sundays this constitutes a failure.

So, yes, there is clearly a failure on the part of the tester (wasn't me) to mock the getCurrentTime() functionality for the purposes of this test - it should have been failing continuously. But I think non-deterministic date parsing is the bigger horror.

qntm fucked around with this message at 15:08 on Dec 30, 2014

Space Kablooey
May 6, 2009


:stare:

DateTime shenanigans aside, your function returns either "0x-zz" or "x-zz"? Or does it depends on what you've passed as the arguments (returns "0x-zz" if your argument is "0a-bb" and returns "x-zz" if your arguments are "a-bb")?

Fake edit: Nevermind, I think I got it, one digit is for the 2000's two digits are for 2010 trough 2099. I hope that you guys don't have data from the last century. Or that somebody is using your software 100 years from now.

Fake edit2: idgi, you are parsing that string, setting that date somewhere and then returning the input string? Or are you converting the current day to your year-weekstring and then checking it?


Since we're on the subject, what is the recommended book for starting with TDD? I think I get the theory behind it, but I never know if I'm doing it right, and I never made a project starting with the tests.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

HardDisk posted:

Since we're on the subject, what is the recommended book for starting with TDD? I think I get the theory behind it, but I never know if I'm doing it right, and I never made a project starting with the tests.

I find that reading a book isn't a good approach for something like this -- it's a mindset you have to get into. Roy Osherove has some good TDD exercises on his site. Bowling is also a good TDD exercise -- the rules are simple, but there are exceptions and special cases.

And remember: When you're writing your tests, write the minimum amount of code: If your first test is "1+1=2", then the body of the method can just return 2. Don't get fancy, you can always go back and refactor once all the tests pass.

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do

HardDisk posted:

Since we're on the subject, what is the recommended book for starting with TDD? I think I get the theory behind it, but I never know if I'm doing it right, and I never made a project starting with the tests.

Growing Object Oriented Software, Guided by Tests is the book we give out at my company's TDD class (we run it for a local university), along with a copy of Fowler's Refactoring.

I can't say I've actually read it and recommend it; I work at a heavy TDD shop, so I've picked up TDD more from that class and from osmosis by pair programming than anything else.

Space Kablooey
May 6, 2009


Thanks for the resources!

Ithaqua posted:

I find that reading a book isn't a good approach for something like this -- it's a mindset you have to get into. Roy Osherove has some good TDD exercises on his site. Bowling is also a good TDD exercise -- the rules are simple, but there are exceptions and special cases.

Yeah, I communicated that badly. I (think I) know the basics + mocking (if that isn't basic for testing poo poo), but I never actually done something that is TDD, so exercises is probably the best thing at the point I am now.

Ithaqua posted:

And remember: When you're writing your tests, write the minimum amount of code: If your first test is "1+1=2", then the body of the method can just return 2. Don't get fancy, you can always go back and refactor once all the tests pass.

That, I still can't wrap my head around.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

HardDisk posted:

That, I still can't wrap my head around.

It's "YAGNI" (ya ain't going to need it) to the extreme.

The idea is that if you want to develop comprehensive unit test suite using TDD, you need to write the unit tests first. If your implementation does more than what the unit tests (in aggregate) say it should, you're not really doing TDD, you're writing code, then testing it. Your unit tests should be comprehensive enough that you end up with a real (albeit potentially kind of crappy) implementation of the functionality as you add more test cases.

Note that this doesn't mean every public/private method in every single class in your project needs to be specifically unit tested. Your component should have an interface (this does not necessarily mean a "C# interface class", this means that your component should have a logical set of methods determining how it's exposed to the outside world.) You only should be writing the unit tests at this level, and later, when you decide to refactor (which is a natural part of the process) you can immediately plug in the replacement and have some confidence that it works the same way as the crappy throwaway implementation you were using to determine what the unit tests should be. This should also mean that bugs should be expressible in terms of failing unit tests.

This means that TDD should be considered more a design tool that allows for re-factoring without breaking code, designing coherent interfaces for your components, and documentation for future developers, rather than a bug-catching tool in and of itself. The issue with writing more code than test is that if your code does more than what the tests can see, the behavior is not covered in the unit tests, and may break in a future "refactored" version. In a code base without unit tests, refactoring becomes a complete gamble because there's really no way of determining whether or not replacement code does the same job as the original code, so any serious refactoring effort will naturally produce bugs and be slow moving.

NovemberMike
Dec 28, 2008

Ithaqua posted:

And remember: When you're writing your tests, write the minimum amount of code: If your first test is "1+1=2", then the body of the method can just return 2. Don't get fancy, you can always go back and refactor once all the tests pass.

I haven't found this to be useful on a practical level. It's a useful training wheel to get people into the habit of writing tests first but it's something you should discard pretty quickly.

qntm
Jun 17, 2009

HardDisk posted:

Fake edit2: idgi, you are parsing that string, setting that date somewhere and then returning the input string? Or are you converting the current day to your year-weekstring and then checking it?

It's a round-trip. We parse the string "00-54" using the date format "YY-ww", to get a date object. We then serialise the date out again using the same date format as before ("YY-ww"), to get a new string ("00-54" or "01-01", depending). It's the result that's being inspected for correctness.

In the case of many date strings and format strings, you might expect to get the same date string afterwards as before. But in other cases, you might not. Imagine if you had input string "00:78:00" and date format "HH:mm:ss". That could be a date error, but it could equally well return "01:18:00".

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

NovemberMike posted:

I haven't found this to be useful on a practical level. It's a useful training wheel to get people into the habit of writing tests first but it's something you should discard pretty quickly.
This is how I feel about TDD in general: great for learning how to write testable code, but only occasionally the best way to actually write things.

NovemberMike
Dec 28, 2008

Plorkyeran posted:

This is how I feel about TDD in general: great for learning how to write testable code, but only occasionally the best way to actually write things.

The problem is that TDD has a lot of cargo cult poo poo associated with it, like that return 2 thing. It's a useful tool for teaching people TDD but if you follow it religiously you end up with a bunch of useless tests that clutter up the project. TDD done properly gives you a scaffold to keep the project from collapsing while you work on it.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

I did several projects sticking to TDD dogma, and what that did was get me into the habit of writing tests early and often.

Nowadays, I kind of write tests and code in parallel. If I'm in the zone, I'll whip up some classes and then go back and write tests to firm up my thinking and API on what I just did. If I'm having trouble seeing the way forward, I'll dick around writing some tests in a more pure TDD way which usually helps me figure out what to do.

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



Thermopyle posted:

I did several projects sticking to TDD dogma, and what that did was get me into the habit of writing tests early and often.

Nowadays, I kind of write tests and code in parallel. If I'm in the zone, I'll whip up some classes and then go back and write tests to firm up my thinking and API on what I just did. If I'm having trouble seeing the way forward, I'll dick around writing some tests in a more pure TDD way which usually helps me figure out what to do.

This is often how I end up coding for myself as well (when I'm not under some constraint). I write up a skeleton that can do a core thing of what I want to do, and then make a test for it. Then as I add parts to it, I make tests for those parts. It seems to work pretty well. I don't usually end up with 100% coverage but I do track the coverage and add tests where I think they're needed, and the tests I have do guarantee a certain minimum of correctness between revisions.

brap
Aug 23, 2004

Grimey Drawer
Yeah people get hysterical that their untested code is gonna spontaneously start doing something insane and that once they write tests for their code it will always give the customer the desired behavior. Neither is particularly true.

Axiem
Oct 19, 2005

I want to leave my mind blank, but I'm terrified of what will happen if I do
Personally, I feel like you shouldn't be writing tests if they don't give you future value, especially around refactoring. I tend to eschew tests for things like factories, where the code is straightforward and has a single path—the test ends up being basically a duplication of the code, which is of little value.

On the other hand, if you have somewhat more complicated behavior, in particular if you end up using branches or loops, then it seems valuable to me to have tests to make sure you get your logic right. To a certain extent, the business logic around how models work is what I'm talking about. You can spec out your tests to state how your objects should behave given particular input, so that if you go back and decide to change the underlying algorithm, you make sure it doesn't change the behavior of the object.

I've started to be a fan of calling it behavior-driven development (BDD) for this reason. What I care about is how my objects behave given input. I really couldn't care less who it calls or what it does along the way, unless I need to stub out a method to provide secondary input (though whenever possible, I prefer using real objects, assuming their behavior is itself well-defined).

An example of this would be in say, a hearts game, when it comes to the object that calculates how many points everyone gets in a round. You can have a test that hearts are worth one point, a test that the queen of spades is worth 13 (even when paired with other hearts), and a test that shooting the moon gives 26 to everyone else. It's behavior that isn't exactly straightforward, and having tests makes sure if you develop some faster way of looping through cards or whatever, you still have the same behavior.

Also, a thing about TDD is that your tests should drive development. It's not just about writing tests first (thereby confirming that you do, in fact, have code coverage)—it's about using your tests to guide development.

An example of this latter thing is harder to explain, but you know it when you see it. Recently, I was building out some tests for a class, and in the process, I was finding it increasingly difficult to write tests to actually hit the code path I wanted, because I needed to do so much setup in stubs and mocks to even hit where I was wanting to test—but in doing so, I realized that the class really needed to be split into two. Doing so suddenly made all of the tests for both classes substantially easier to write (and therefore, understand later), while more clearly clarifying what the code did and how it did it. Plus, it's made the objects more comprehensible on their own, and overall feels like a better architecture.

Like all things, though, TDD is a tool. TDD alone won't create great code—but it can help you write better code by forcing you to think more clearly about your boundaries between classes. Use it if it brings you value (or if you're trying to wrap your head around it); don't use it if it doesn't.

qntm
Jun 17, 2009
Test driven development has its pros and cons but test-driven defect fixing is pretty difficult to argue with. Someone reports a problem with the program, the first thing you do is write a minimal failing test case and put it into your regression suite.

lord funk
Feb 16, 2004

Can you all answer a dumb question for me: is TDD at all useful for catching UI issues, or is it only for model / framework testing?

sarehu
Apr 20, 2007

(call/cc call/cc)
TDD isn't "testing," it's orthogonal to the question of whether you have tests.

For UI stuff it'd be real annoying because you'd be writing UI tests before writing the UI, and that just slows down the UI design iteration process down because the tight loop 99% of the time should be around quality of user interaction.

sarehu fucked around with this message at 15:14 on Dec 31, 2014

TheresaJayne
Jul 1, 2011

Suspicious Dish posted:

I mean, it's not like there's any better choice when dealing with times, because we're sincerely hosed, but why does the year start on the first Thursday?

Could it be that the epoch Jan 1st 1970 was a thursday....

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

fleshweasel posted:

Yeah people get hysterical that their untested code is gonna spontaneously start doing something insane and that once they write tests for their code it will always give the customer the desired behavior. Neither is particularly true.

Only a programmer deals in absolutes.

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



Suspicious Dish posted:

I mean, it's not like there's any better choice when dealing with times, because we're sincerely hosed, but why does the year start on the first Thursday?

I think it's just another way of saying that the first week of the year is the one where more days are on or after jan 1st than before?

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.

sarehu posted:

TDD isn't "testing," it's orthogonal to the question of whether you have tests.

For UI stuff it'd be real annoying because you'd be writing UI tests before writing the UI, and that just slows down the UI design iteration process down because the tight loop 99% of the time should be around quality of user interaction.

Yeah, in order to make TDD work there you really need to figure out ways to write relevant UI tests without blocking iteration on the softer parts which will constantly be tweaked. If you have ideal separation of concerns, then you'd test all the actor method/function calls which result in changes in the world state -- they usually have a fairly straightforward test case, and treat the actual fuzzy UI bit as implementation detail and therefore not tested. At least until iteration is finished and you can actually be certain tests such as click x and y happens won't be invalidated.

Adbot
ADBOT LOVES YOU

seiken
Feb 7, 2005

hah ha ha

Ithaqua posted:

And remember: When you're writing your tests, write the minimum amount of code: If your first test is "1+1=2", then the body of the method can just return 2. Don't get fancy, you can always go back and refactor once all the tests pass.

step 1: write a bunch of tests and make sure they all pass despite your code being completely and utterly broken. This way you know that the tests are reliably judging the correctness of the code.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply