¿ªÔÆÌåÓý

ctrl + shift + ? for shortcuts
© 2025 Groups.io

Re: "bottom-up" TDD and common behaviors

 

If I understand correctly, the code here is specifically?for doing an Ecto transformation, correct? If you decide not to use Ecto the need for this abstraction is removed?

brought to you by the letters A, V, and I
and the number 47


On Tue, Dec 3, 2019 at 2:18 AM Brian Marick <marick@...> wrote:
TL;DR: For various reasons, I was trying to avoid the use of mocks in this app. I¡¯m asking how a particular problem would be nicely solved without them.?

I should note that I have a guideline that a test should contain no words except those that highlight what¡¯s special about it - about what the test is *for*.

------------------


Let me explain the issue better, or at least more. Here is a form:



That represents one row from an `animals` table. It also represents two rows from a `service_gaps` table, specifically two rows with a foreign key that points at the animal.?

Ecto is an Elixir structure-to-relational-table mapper. It¡¯s easy to ask it for the animal plus its service gaps, in which case it does all the appropriate joins and produces a structure that looks like this (with some fields stripped for concision):


That looks different than what the form displays. Somehow, the nil `out_of_service_date` has been turned into the string ¡°never¡±, and the `span` structure in the service gap has been ¡°flattened¡± into two strings. That is, you could imagine that what¡¯s actually rendered is a derivative structure like this:


If you imagined that, you¡¯d be wrong. Ecto really wants you to put the actual database fields and also the ¡°virtual¡± fields that hold form values into a single structure that looks like this:


***Whether it's a good idea for a database mapper to know a bunch of things about how the client works is NOT at issue here. Ecto is what it is.***

When you read an animal from the database, it comes back as the previous structure with the three highlighted lines set to `nil`. That¡¯s suitable for lots of operations on animals, but it¡¯s not suitable for producing a form that can be readily used to update an animal and its service gaps. For that, you need to derive the appropriate values for the highlighted fields (fill them in as shown). Once you do that, it¡¯s *really easy* to write code that takes the result of an HTTP POST and updates the database: atomically applying all the changes from the form data, including creating a new ¡°service gaps¡± row. (The rather grotty data structure makes for simpler code, which is why I still don¡¯t know what to think about the design of the Ecto library.)

So let¡¯s consider a function that converts an animal `id` into an initialized form. That function is called when a user clicks on a table element like this:


¡­ and it produces an `Animal` structure like the one above. Here¡¯s an implementation of that function:


It has two responsibilities:?

1. Fetch the corresponding animal in the normal way, including the associated service gaps (etc.)?
2. Augment that data to make it suitable for a form.

In a mockish approach, I¡¯d TDD that with pseudocode like this:

? ?updatable(5, ¡°test¡±) produces `..result..`
? ?provided
? ? ? ?Read.one([id: 5], ¡°test¡±) produces `..animal..`, and
? ? ? ?Read.put_updatable_fields(`..animal..`) produces `..result..`

(The `..animal..` notation is for what I call ¡°metaconstants¡±, which are values about which nothing is known except their name and that two instances of the same name refer to the same value. My Midje library for Clojure has metaconstants built in, so you *can¡¯t* do anything else with them. In a dynamically-typed language, it¡¯s easy to use strings or symbols for the same thing. Static typing makes metaconstants much harder.)

I like this test because it doesn't set up specific animal data that gets checked for facts that *imply* that updatability was handled correctly. It says it directly: ?¡°An updatable animal N is an existing animal that¡¯s read and then modified to be updatable¡±. I like to think of such tests as being like proofs that use lemmas: *if* animal reading works correctly, and making an animal updatable works correctly, then fetching an updatable animal is works correctly.?

(That is, I¡¯m working at the conceptual level, not the implementation level, so the ¡°you¡¯re just testing implementation¡± argument against mocks doesn¡¯t apply. After all, *shouldn¡¯t* our implementations be structured around relevant concepts?)

However, for various reasons, I was trying to avoid the use of mocks in this app. So, if you were doing this in a non-mockish way, what tests would you have? (Remember, there are four functions that do pretty much the same thing.)




Re: "bottom-up" TDD and common behaviors

 

¿ªÔÆÌåÓý

TL;DR: For various reasons, I was trying to avoid the use of mocks in this app. I¡¯m asking how a particular problem would be nicely solved without them.?

I should note that I have a guideline that a test should contain no words except those that highlight what¡¯s special about it - about what the test is *for*.

------------------


Let me explain the issue better, or at least more. Here is a form:



That represents one row from an `animals` table. It also represents two rows from a `service_gaps` table, specifically two rows with a foreign key that points at the animal.?

Ecto is an Elixir structure-to-relational-table mapper. It¡¯s easy to ask it for the animal plus its service gaps, in which case it does all the appropriate joins and produces a structure that looks like this (with some fields stripped for concision):


That looks different than what the form displays. Somehow, the nil `out_of_service_date` has been turned into the string ¡°never¡±, and the `span` structure in the service gap has been ¡°flattened¡± into two strings. That is, you could imagine that what¡¯s actually rendered is a derivative structure like this:


If you imagined that, you¡¯d be wrong. Ecto really wants you to put the actual database fields and also the ¡°virtual¡± fields that hold form values into a single structure that looks like this:


***Whether it's a good idea for a database mapper to know a bunch of things about how the client works is NOT at issue here. Ecto is what it is.***

When you read an animal from the database, it comes back as the previous structure with the three highlighted lines set to `nil`. That¡¯s suitable for lots of operations on animals, but it¡¯s not suitable for producing a form that can be readily used to update an animal and its service gaps. For that, you need to derive the appropriate values for the highlighted fields (fill them in as shown). Once you do that, it¡¯s *really easy* to write code that takes the result of an HTTP POST and updates the database: atomically applying all the changes from the form data, including creating a new ¡°service gaps¡± row. (The rather grotty data structure makes for simpler code, which is why I still don¡¯t know what to think about the design of the Ecto library.)

So let¡¯s consider a function that converts an animal `id` into an initialized form. That function is called when a user clicks on a table element like this:


¡­ and it produces an `Animal` structure like the one above. Here¡¯s an implementation of that function:


It has two responsibilities:?

1. Fetch the corresponding animal in the normal way, including the associated service gaps (etc.)?
2. Augment that data to make it suitable for a form.

In a mockish approach, I¡¯d TDD that with pseudocode like this:

? ?updatable(5, ¡°test¡±) produces `..result..`
? ?provided
? ? ? ?Read.one([id: 5], ¡°test¡±) produces `..animal..`, and
? ? ? ?Read.put_updatable_fields(`..animal..`) produces `..result..`

(The `..animal..` notation is for what I call ¡°metaconstants¡±, which are values about which nothing is known except their name and that two instances of the same name refer to the same value. My Midje library for Clojure has metaconstants built in, so you *can¡¯t* do anything else with them. In a dynamically-typed language, it¡¯s easy to use strings or symbols for the same thing. Static typing makes metaconstants much harder.)

I like this test because it doesn't set up specific animal data that gets checked for facts that *imply* that updatability was handled correctly. It says it directly: ?¡°An updatable animal N is an existing animal that¡¯s read and then modified to be updatable¡±. I like to think of such tests as being like proofs that use lemmas: *if* animal reading works correctly, and making an animal updatable works correctly, then fetching an updatable animal is works correctly.?

(That is, I¡¯m working at the conceptual level, not the implementation level, so the ¡°you¡¯re just testing implementation¡± argument against mocks doesn¡¯t apply. After all, *shouldn¡¯t* our implementations be structured around relevant concepts?)

However, for various reasons, I was trying to avoid the use of mocks in this app. So, if you were doing this in a non-mockish way, what tests would you have? (Remember, there are four functions that do pretty much the same thing.)




Re: "bottom-up" TDD and common behaviors

 

¿ªÔÆÌåÓý

We still don't know the context, but it seems like we have some kind of a thing that either has fields that are sometimes mod and sometimes not, or sometimes has mod fields added to it. That could be built in lots of interesting ways, as with an adapter that covers up the fields making them unmodifiable, or a partner object adapter that knows the secret handshake.

My basic approach would be to ask the question I want to know the answer to, roughly, "are those fields modifiable", and then let the code tell me more about the implementation. If that question became more complex to answer, that might be just fine.

Without building the thing, I cannot know.?

On Dec 2, 2019, at 2:48 PM, Steve Gordon <sgordonphd@...> wrote:

What motivates implementing a setter method under TDD unless there is a test that requires it to exist and work?? Extra tests would only be required if we also need to implement is<X>Modifiable() for some field X.


Ron Jeffries
Perfectionism is the voice of the oppressor -- Anne Lamott


Re: "bottom-up" TDD and common behaviors

 

What motivates implementing a setter method under TDD unless there is a test that requires it to exist and work?? Extra tests would only be required if we also need to implement is<X>Modifiable() for some field X.


On Mon, Dec 2, 2019 at 12:26 PM Ron Jeffries <ronjeffriesacm@...> wrote:
If we're gonna be like that, wouldn't you need a test for every modifiable field? :)

On Dec 2, 2019, at 11:16 AM, Steve Gordon <sgordonphd@...> wrote:

Just because an object has a method implemented to "know" whether or not a field is modifiable?does not mean that that method is correctly implemented.? If there is such a method, you would still have to have at least two tests that verifies returns true only when that field is actually modifiable and false only when it is not.??

Unless the application itself needs such a method, I would have a test that gets the fields value, sets it to a different value, and gets the field value to verify it changes.


Ron Jeffries

Master your instrument, master the music, then forget all that shit and just play. -- Charlie Parker


Re: "bottom-up" TDD and common behaviors

 

¿ªÔÆÌåÓý

If we're gonna be like that, wouldn't you need a test for every modifiable field? :)

On Dec 2, 2019, at 11:16 AM, Steve Gordon <sgordonphd@...> wrote:

Just because an object has a method implemented to "know" whether or not a field is modifiable?does not mean that that method is correctly implemented.? If there is such a method, you would still have to have at least two tests that verifies returns true only when that field is actually modifiable and false only when it is not.??

Unless the application itself needs such a method, I would have a test that gets the fields value, sets it to a different value, and gets the field value to verify it changes.


Ron Jeffries

Master your instrument, master the music, then forget all that shit and just play. -- Charlie Parker


Re: "bottom-up" TDD and common behaviors

 

Just because an object has a method implemented to "know" whether or not a field is modifiable?does not mean that that method is correctly implemented.? If there is such a method, you would still have to have at least two tests that verifies returns true only when that field is actually modifiable and false only when it is not.??

Unless the application itself needs such a method, I would have a test that gets the fields value, sets it to a different value, and gets the field value to verify it changes.

On Mon, Dec 2, 2019 at 6:30 AM Ron Jeffries <ronjeffriesacm@...> wrote:
Yes. And if I didn't mind modifying a field, testing it that way is OK.
If I knew the context I'd have a better idea but as it stands I'm thinking my object must know whether it can modify fields or not. I suppose a modifyField operation might return T/F ...

R

On Dec 2, 2019, at 8:18 AM, Avi Kessner <akessner@...> wrote:

Best to test to behaviour, not implementation/capability, I think.


Ron Jeffries
If it is more than you need, it is waste. -- Andy Seidl


Re: "bottom-up" TDD and common behaviors

 

¿ªÔÆÌåÓý

Yes. And if I didn't mind modifying a field, testing it that way is OK.
If I knew the context I'd have a better idea but as it stands I'm thinking my object must know whether it can modify fields or not. I suppose a modifyField operation might return T/F ...

R

On Dec 2, 2019, at 8:18 AM, Avi Kessner <akessner@...> wrote:

Best to test to behaviour, not implementation/capability, I think.


Ron Jeffries
If it is more than you need, it is waste. -- Andy Seidl


Re: "bottom-up" TDD and common behaviors

 

Best to test to behaviour, not implementation/capability, I think.

brought to you by the letters A, V, and I
and the number 47


On Mon, Dec 2, 2019 at 2:33 PM Ron Jeffries <ronjeffriesacm@...> wrote:
I was thinking I'd ask the object if it had updatable fields, but it'd depend on an understanding of the problem and solution that I don't presently have.

On Dec 2, 2019, at 7:26 AM, Alan Baljeu via Groups.Io <alanbaljeu@...> wrote:

The way I test if animals have updatable fields, I try to update a field and check that it updated.


Ron Jeffries
If another does not intend offense, it is wrong for me to seek it;
if another does indeed intend offense, it is foolish for me to permit it.
? -- Kelly Easterley


Re: "bottom-up" TDD and common behaviors

 

¿ªÔÆÌåÓý

I was thinking I'd ask the object if it had updatable fields, but it'd depend on an understanding of the problem and solution that I don't presently have.

On Dec 2, 2019, at 7:26 AM, Alan Baljeu via Groups.Io <alanbaljeu@...> wrote:

The way I test if animals have updatable fields, I try to update a field and check that it updated.


Ron Jeffries
If another does not intend offense, it is wrong for me to seek it;
if another does indeed intend offense, it is foolish for me to permit it.
? -- Kelly Easterley


Re: "bottom-up" TDD and common behaviors

 

The way I test if animals have updatable fields, I try to update a field and check that it updated.

Alan Baljeu
alanbaljeu@...



On Sunday, December 1, 2019, 07:16:01 p.m. EST, Brian Marick <marick@...> wrote:


What I¡¯m guessing is that you invent an assertion that, when true of the return value, implies that it has been made ¡°with updatable fields¡±. So it¡¯s a property of the data rather than a property of how it was created.

Yeah, that probably makes sense. Forget I asked.

On Dec 1, 2019, at 6:07 PM, Brian Marick <marick@...> wrote:

Here¡¯s some code I have:

<Screen Shot 2019-12-01 at 5.55.54 PM.png>


Here¡¯s a correctness claim about that code: ¡°any function that returns one or more Animals must ensure that those animals have ¡®updatable fields¡¯¡±. I come from a mockish tradition, in which that claim would be stated directly by an assertion that `put_updatable_fields` would be called and be used as the return value.?

I¡¯ve been trying to do non-mockish testing in this app, and I¡¯ve gotten myself all bollixed up. Without mocks, what would tests for these four functions look like?

I think I once knew the answers to such questions, but I can¡¯t remember them.


Re: "bottom-up" TDD and common behaviors

 

¿ªÔÆÌåÓý

What I¡¯m guessing is that you invent an assertion that, when true of the return value, implies that it has been made ¡°with updatable fields¡±. So it¡¯s a property of the data rather than a property of how it was created.

Yeah, that probably makes sense. Forget I asked.

On Dec 1, 2019, at 6:07 PM, Brian Marick <marick@...> wrote:

Here¡¯s some code I have:

<Screen Shot 2019-12-01 at 5.55.54 PM.png>


Here¡¯s a correctness claim about that code: ¡°any function that returns one or more Animals must ensure that those animals have ¡®updatable fields¡¯¡±. I come from a mockish tradition, in which that claim would be stated directly by an assertion that `put_updatable_fields` would be called and be used as the return value.?

I¡¯ve been trying to do non-mockish testing in this app, and I¡¯ve gotten myself all bollixed up. Without mocks, what would tests for these four functions look like?

I think I once knew the answers to such questions, but I can¡¯t remember them.


"bottom-up" TDD and common behaviors

 

Here¡¯s some code I have:



Here¡¯s a correctness claim about that code: ¡°any function that returns one or more Animals must ensure that those animals have ¡®updatable fields¡¯¡±. I come from a mockish tradition, in which that claim would be stated directly by an assertion that `put_updatable_fields` would be called and be used as the return value.?

I¡¯ve been trying to do non-mockish testing in this app, and I¡¯ve gotten myself all bollixed up. Without mocks, what would tests for these four functions look like?

I think I once knew the answers to such questions, but I can¡¯t remember them.


Re: REQ: Moderators

 

Thank you, everyone, who volunteered. I think we have enough for now.

You who have become moderators will notice new emails notifying you of messages waiting for approval. View them online, where you will easily be able to approve the messages and remove the poster from moderation OR reject the messages and possibly ban the poster.

If anyone notices that messages stay pending for several days, then we need more moderators. In that case, just say so. :)

Thank you!
--
J. B. (Joe) Rainsberger :: :: ::
Teaching evolutionary design and TDD since 2002


Re: "Find or Create" functions: a discussion

 

I have a system that is doing this part of the time.? It is fraught with problems when doing the search.? In your case, searching for "John Smith" may return a set of records, while the creation is creating a record which needs some unique identifier for the real John Smith you want to add to the database.? Even just using first name and last name , or partial of SSN , etc? makes for complicated code for what keys you are going to use , are those keys also using SOUNDEX() feature of SQL ?? For those who will follow you, just make it classical CRUD application without mixed or confusing methods or functions.?


Re: REQ: Moderators

 

Hi J.B.

If you still need moderators, then I'll volunteer?to help.?

Let me know what?you need me to do.

Thanks,
Rick

On Mon, Nov 25, 2019 at 8:07 AM J. B. Rainsberger <[email protected]> wrote:
Hi, folks.

We need moderators. Please volunteer!

Your central responsibility involves approving new messages and new members. We will have a significant amount of old-new traffic for the next few weeks as people return to the group. I would prefer not to continue to act as the bottleneck. :)

When a "new" member writes a not-obviously-horrible message for the first time, I approve the message and turn moderation off for them. I ban people who spam us. Mostly, that's it.

Thanks!
--
J. B. (Joe) Rainsberger :: :: ::
Teaching evolutionary design and TDD since 2002


Re: REQ: Moderators

Guilherme Froes
 

I volunteer!

-Guilherme Froes

Em seg., 25 de nov. de 2019 ¨¤s 10:07, J. B. Rainsberger <[email protected]> escreveu:

Hi, folks.

We need moderators. Please volunteer!

Your central responsibility involves approving new messages and new members. We will have a significant amount of old-new traffic for the next few weeks as people return to the group. I would prefer not to continue to act as the bottleneck. :)

When a "new" member writes a not-obviously-horrible message for the first time, I approve the message and turn moderation off for them. I ban people who spam us. Mostly, that's it.

Thanks!
--
J. B. (Joe) Rainsberger :: :: ::
Teaching evolutionary design and TDD since 2002


Re: "I think the community needs more explicit direction...."

 

On Mon, Nov 25, 2019 at 10:22 AM Steve Gordon <sgordonphd@...> wrote:

On Mon, Nov 25, 2019 at 11:07 AM Edwin Castro <egcastr@...> wrote:


Or perhaps we just don't do enough teaching design prior to the workforce. Should we solve problems in school? Yes, we learn from trying things out and failing and trying again. But should we have problems to solve or solutions to design to meet certain criteria? The difference might be subtle and students who have spent their entire K-12 learning career mostly memorizing facts and solving math problems with single answers will always find it easier to "solve a problem" rather than design a solution.

--
Edwin G. Castro


When I was a professor, all I taught was problem solving.? Students hated it because they could not just memorize terms for my tests, and the student evaluations reflected it.? Grading also took a lot of time away from research because unlike my fellow professor's multiple choice tests, I actually had to read my student's solutions.? It was a lose-lose for my academic career.??

The invention of the automatically graded, multiple-choice test is what lead to the slow erosion of American education.? Not everything should be automated.
??
So is education a lost cause? Surely not. I hope not!

Are we trying to "educate" too quickly? Should we provide more time for students to read, try some problems on their own, and then and only then provide lectures to help cement their understanding? Today we do it backward and students, in my opinion, are encouraged to memorize by the presentation format. There is no time to internalize any information and then tests reinforce the notion that memorization is the best approach. Are we really preparing students for their future this way?

What are other countries doing? Are we seeing the same behaviors outside the US as well?


Re: REQ: Moderators

 

Also happy to help.


On Mon, 25 Nov 2019 at 13:07, J. B. Rainsberger <[email protected]> wrote:
Hi, folks.

We need moderators. Please volunteer!

Your central responsibility involves approving new messages and new members. We will have a significant amount of old-new traffic for the next few weeks as people return to the group. I would prefer not to continue to act as the bottleneck. :)

When a "new" member writes a not-obviously-horrible message for the first time, I approve the message and turn moderation off for them. I ban people who spam us. Mostly, that's it.

Thanks!
--
J. B. (Joe) Rainsberger :: :: ::
Teaching evolutionary design and TDD since 2002




Re: "I think the community needs more explicit direction...."

 



On Mon, Nov 25, 2019 at 11:07 AM Edwin Castro <egcastr@...> wrote:


Or perhaps we just don't do enough teaching design prior to the workforce. Should we solve problems in school? Yes, we learn from trying things out and failing and trying again. But should we have problems to solve or solutions to design to meet certain criteria? The difference might be subtle and students who have spent their entire K-12 learning career mostly memorizing facts and solving math problems with single answers will always find it easier to "solve a problem" rather than design a solution.

--
Edwin G. Castro


When I was a professor, all I taught was problem solving.? Students hated it because they could not just memorize terms for my tests, and the student evaluations reflected it.? Grading also took a lot of time away from research because unlike my fellow professor's multiple choice tests, I actually had to read my student's solutions.? It was a lose-lose for my academic career.??

The invention of the automatically graded, multiple-choice test is what lead to the slow erosion of American education.? Not everything should be automated.



Re: "I think the community needs more explicit direction...."

 

¿ªÔÆÌåÓý

Since the busy days of this list all those years ago I¡¯ve retired, but I still code in partnership with my son.

He¡¯s fairly receptive to the idea of TDD, less interested in the refactoring part. He doesn¡¯t like reading either.

The way we work usually is that he explains some functional requirement and I create a library ¨C nicely TDD¡¯d of course.

He¡¯s dabbled with TDD but usually he¡¯ll just jump straight into code.

?

To be fair, he works at the visual interface end, the UX.

And has produced some interesting stuff with front-ends such as Unity.

?

Nice to see all these names in my inbox again ?

?

John D.