Re: [testdrivendevelopment] "bottom-up" TDD and common behaviors
"Steve Gordon" <[email protected]> Thu, 5 Dec 2019 21:41:46 -0700
| Newsgroups | gmane.comp.programming.test-driven-development |
|---|---|
| Message-ID | <CAF7qo6XVvmikUgR-tD=ZLx=do0gb8fxZUreJsfiJB+BiPSrWvA@mail.gmail.com> |
--0000000000007d07c3059901aae7 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Faster and cheaper to program does not mean easier to maintain, especially if the long term owner of the code is maintaining dozens of applications written by different teams with different ideas about what is faster, cheaper, efficient and expressive. When a framework is chosen, there are reasons, which may indeed include assumptions about the long term maintenance cost of lots of applications. Ask why in case respecting the choice of framework is more in the customer's long term interest than abstracting the framework into your way of coding. In XP, we endeavor to write logic in the business domain language instead of the technical language of bits, bytes, programatic structures, data structures, database records, datastores, etc. On Thu, Dec 5, 2019 at 7:00 PM Daniel Olewski <[email protected]> wrote: > In my experience the separation of application logic and externals is mu= ch > faster and cheaper than most think. Even more including any long-term > benefits when things change. It=E2=80=99s just one of the code design ac= tivities > which we do anyways. Pays off in weeks =E2=80=93 not years =E2=80=A6 . > > > > `store-record()` to me implies storing in a single db record, which leak= s > =E2=80=98db=E2=80=99 term into this surface. > > `employee_storage.store(employee)` is more general =E2=80=93 don=E2=80= =99t care if it=E2=80=99s > storing in a record, many records or somewhere else. That=E2=80=99s why = I prefer > the latter. > > > > employee.store() =E2=80=93 this seems to imply that the employee needs t= o know how > to store/retrieve itself? That=E2=80=99s a coupling I=E2=80=99d rather a= void =E2=80=93 I=E2=80=99d rather > couple to a shape of data (Employee) and pass it around freely across > classes/processes/languages/operating system/computers =E2=80=A6 . Emplo= yee would > typically already have a single responsibility of keeping itself valid > (what=E2=80=99s required/optional, valid values, etc.) =E2=80=93 why add= another > responsibility and more coupling? > > > > *From: *<[email protected]> on behalf of Steve Gordon < > [email protected]> > *Reply-To: *"[email protected]" < > [email protected]> > *Date: *Thursday, December 5, 2019 at 5:38 PM > *To: *"[email protected]" <[email protected]= > > *Subject: *Re: [testdrivendevelopment] "bottom-up" TDD and common > behaviors > > > > We should listen to our paying customers who may have some thoughts on t= he > future of their company and their application. They may not want to pay > for the extra time and effort to abstract a framework that they may have > chosen for a specific business reason, They may prefer to be maintainin= g a > family of applications that leverage the same framework in the obvious > direct way instead of a family of applications where each team decides t= o > abstract that framework away in subtly different ways. > > > > However, if I am abstracting out the database, I much > prefect employee.store() over employee-storage.store_record(). Why shou= ld > I impose "_storage" and "_record" on code that is abstracting the databa= se > details? > > > > On Thu, Dec 5, 2019 at 5:47 PM Daniel Olewski <[email protected]> wrote: > > All frameworks change eventually, or stop working when say OS version is > updated. Many of us have learned that the hard way =E2=80=A6 . > > Inventing a new RDBMS interface =E2=80=93 that means leaking RDBMS world= into your > application domain. And perhaps also implies the bigger work of covering > all of RDBMS functionality. When we use RDBMS it=E2=80=99s just for stor= age of data > =E2=80=A6 today. Tomorrow it can be a blob in the cloud, next year it wi= ll be > something different. I do want my code to be flexible for all those. One > way to do that is to isolate on the edge of how the app domain logic use= s > the storage. Think `employee_storage.store_employee()` vs > `rdbms.insert_record()`. A nuance, but an important one IMO. Once we hav= e > that =E2=80=93 the app won=E2=80=99t care how the storage is implemented= and a simple > =E2=80=98in-memory employee storage=E2=80=99 or =E2=80=98local-file empl= oyee storage=E2=80=99 will suffice > for unit or some integration testing .. > > > > *From: *<[email protected]> on behalf of Brian Marick < > [email protected]> > *Reply-To: *"[email protected]" < > [email protected]> > *Date: *Thursday, December 5, 2019 at 4:21 PM > *To: *"[email protected]" <[email protected]= > > *Subject: *Re: [testdrivendevelopment] "bottom-up" TDD and common > behaviors > > > > That raises an interesting general question. > > > > "The technology" is a web framework and its linked database framework. > > > > The risk of those changing in a way that breaks a lot of old code is > pretty small. How much effort should we spend insulating our code agains= t > low-probability events? > > > > Isolating my code from Ecto would in effect mean inventing a *new* > interface to a RDBMS. Does it really seem likely that I=E2=80=99ll do th= at better > than the Ecto designers? > > > > P.S. I need to spend some time thinking about how FP ideas and OO ideas > play together. My opinion has been that, leaving aside inheritance, typi= cal > FP languages are not different, in practice, than OO languages. But I > wonder if that=E2=80=99s right. > > > > On Dec 4, 2019, at 12:43 AM, Avi Kessner <[email protected]> wrote: > > > > So this is definitely required behavior and it will be your own, so it > needs to be tested. > > On the other hand, it's a very specific implementation detail which coul= d > change when the technology changes and we don't want that to impact actu= al > behavior related tests about animals. > > > > What I would do is make a transformation decorator and then test sample > data to see that it gets transformed correctly. If Ecto ever changes, t= hat > transformation decorator can do nothing if needed. > > You basically need a map of fields that can be changed and the > transformation needed for that field. > > > > A bit more work, but it allows for a change in Ecto or a change in > understanding of Ecto to not impact the main test suite. > > > > On Wed, Dec 4, 2019, 01:50 Brian Marick <[email protected]> wrote: > > Yes. > > > > On Dec 3, 2019, at 5:31 AM, Avi Kessner <[email protected]> wrote: > > > > If I understand correctly, the code here is specifically for doing an Ec= to > transformation, correct? If you decide not to use Ecto the need for this > abstraction is removed? > > > > > > > > > >=20 > > -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#35814): https://groups.io/g/testdrivendevelopment/mess= age/35814 Mute This Topic: https://groups.io/mt/64491946/3268755 Group Owner: [email protected] Unsubscribe: https://groups.io/g/testdrivendevelopment/leave/6156322/74455= 6386/xyzzy [[email protected]] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --0000000000007d07c3059901aae7 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div>Faster and cheaper to program does not mean easier to= maintain, especially if the long term owner of the code is maintaining doz= ens of applications written by different teams with different ideas about w= hat is faster, cheaper, efficient and expressive.=C2=A0 When a framework is= chosen, there are reasons, which may indeed include assumptions about the = long term maintenance cost of lots of applications.=C2=A0 Ask why in case r= especting the choice of framework is more in the customer's long term i= nterest than abstracting the framework into your way of coding.</div><div><= br></div>In XP, we endeavor to write logic in the business domain language = instead of the technical language of bits, bytes, programatic structures, d= ata structures, database records, datastores, etc.=C2=A0=C2=A0<div><br></di= v><div><br><div><br></div><div><br></div></div></div><br><div class=3D"gmai= l_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Thu, Dec 5, 2019 at 7:00 = PM Daniel Olewski <<a href=3D"mailto:[email protected]">[email protected]<= /a>> wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0= px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> <div lang=3D"EN-US"> <div class=3D"gmail-m_-454653949809025468WordSection1"> <p class=3D"MsoNormal">In my experience the separation of application logi= c and externals is much faster and cheaper than most think. Even more inclu= ding any long-term benefits when things change. It=E2=80=99s just one of th= e code design activities which we do anyways. Pays off in weeks =E2=80=93 not years =E2=80=A6 . <u></u><u></u></p> <p class=3D"MsoNormal"><u></u>=C2=A0<u></u></p> <p class=3D"MsoNormal">`store-record()` to me implies storing in a single = db record, which leaks =E2=80=98db=E2=80=99 term into this surface. <u></u><u></u></p> <p class=3D"MsoNormal">`employee_storage.store(employee)` is more general = = =E2=80=93 don=E2=80=99t care if it=E2=80=99s storing in a record, many rec= ords or somewhere else. That=E2=80=99s why I prefer the latter.<u></u><u></= u></p> <p class=3D"MsoNormal"><u></u>=C2=A0<u></u></p> <p class=3D"MsoNormal">employee.store() =E2=80=93 this seems to imply that= the employee needs to know how to store/retrieve itself? That=E2=80=99s a = coupling I=E2=80=99d rather avoid =E2=80=93 I=E2=80=99d rather couple to a = shape of data (Employee) and pass it around freely across classes/processes= /languages/operating system/computers =E2=80=A6 . Employee would typically already have a sing= le responsibility of keeping itself valid (what=E2=80=99s required/optional= , valid values, etc.) =E2=80=93 why add another responsibility and more cou= pling?<u></u><u></u></p> <p class=3D"MsoNormal"><u></u>=C2=A0<u></u></p> <div style=3D"border-right:none;border-bottom:none;border-left:none;border= -top:1pt solid rgb(181,196,223);padding:3pt 0in 0in"> <p class=3D"MsoNormal"><b><span style=3D"font-size:12pt;color:black">From:= </span></b><span style=3D"font-size:12pt;color:black"><<a href=3D"mailt= o:[email protected]" target=3D"_blank">testdrivendevelopment@= groups.io</a>> on behalf of Steve Gordon <<a href=3D"mailto:sgordonph= [email protected]" target=3D"_blank">[email protected]</a>><br> <b>Reply-To: </b>"<a href=3D"mailto:[email protected]" = target=3D"_blank">[email protected]</a>" <<a href=3D"= mailto:[email protected]" target=3D"_blank">testdrivendevelop= [email protected]</a>><br> <b>Date: </b>Thursday, December 5, 2019 at 5:38 PM<br> <b>To: </b>"<a href=3D"mailto:[email protected]" target= = =3D"_blank">[email protected]</a>" <<a href=3D"mailt= o:[email protected]" target=3D"_blank">testdrivendevelopment@= groups.io</a>><br> <b>Subject: </b>Re: [testdrivendevelopment] "bottom-up" TDD and = common behaviors<u></u><u></u></span></p> </div> <div> <p class=3D"MsoNormal"><u></u>=C2=A0<u></u></p> </div> <div> <p class=3D"MsoNormal">We should listen to our paying customers who may ha= ve some thoughts on the future of their company and their application.=C2= =A0 They may not want to pay for the extra time and effort to abstract a f= ramework=C2=A0that they may have chosen for a specific business reason,=C2=A0 They=C2=A0may prefer to be maintaining a family of= applications that leverage the same framework in the obvious direct way in= stead of a family of applications where each team decides to abstract that = framework away in subtly=C2=A0different ways. <u></u><u></u></p> <div> <p class=3D"MsoNormal"><u></u>=C2=A0<u></u></p> </div> <div> <p class=3D"MsoNormal">However, if I am abstracting out the database, I mu= ch prefect=C2=A0employee.store() over employee-storage.store_record().=C2= =A0 Why should I impose "_storage" and "_record" on co= de that is abstracting the database details?<u></u><u></u></p> </div> </div> <p class=3D"MsoNormal"><u></u>=C2=A0<u></u></p> <div> <div> <p class=3D"MsoNormal">On Thu, Dec 5, 2019 at 5:47 PM Daniel Olewski <<= a href=3D"mailto:[email protected]" target=3D"_blank">[email protected]</a>&g= t; wrote:<u></u><u></u></p> </div> <blockquote style=3D"border-top:none;border-right:none;border-bottom:none;= border-left:1pt solid rgb(204,204,204);padding:0in 0in 0in 6pt;margin-left:= 4.8pt;margin-right:0in"> <div> <div> <p class=3D"MsoNormal">All frameworks change eventually, or stop working w= hen say OS version is updated. Many of us have learned that the hard way = =E2=80=A6 .<u></u><u></u></p> <p class=3D"MsoNormal">Inventing a new RDBMS interface =E2=80=93 that mean= s leaking RDBMS world into your application domain. And perhaps also implie= s the bigger work of covering all of RDBMS functionality. When we use RDBMS it=E2=80=99s just for storage of data =E2=80=A6 today. Tomor= row it can be a blob in the cloud, next year it will be something different= . I do want my code to be flexible for all those. One way to do that is to = isolate on the edge of how the app domain logic uses the storage. Think `employee_storage.store_employee()` vs `rdbms.insert_r= ecord()`. A nuance, but an important one IMO. Once we have that =E2=80=93 t= he app won=E2=80=99t care how the storage is implemented and a simple =E2= =80=98in-memory employee storage=E2=80=99 or =E2=80=98local-file employee = storage=E2=80=99 will suffice for unit or some integration testing .. <u></u><u></u></p> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> <div style=3D"border-right:none;border-bottom:none;border-left:none;border= -top:1pt solid rgb(181,196,223);padding:3pt 0in 0in"> <p class=3D"MsoNormal"><b><span style=3D"font-size:12pt;color:black">From: </span></b><span style=3D"font-size:12pt;color:black"><<a href=3D"mailt= o:[email protected]" target=3D"_blank">testdrivendevelopment@= groups.io</a>> on behalf of Brian Marick <<a href=3D"mailto:marick@ex= ampler.com" target=3D"_blank">[email protected]</a>><br> <b>Reply-To: </b>"<a href=3D"mailto:[email protected]" = target=3D"_blank">[email protected]</a>" <<a href=3D"= mailto:[email protected]" target=3D"_blank">testdrivendevelop= [email protected]</a>><br> <b>Date: </b>Thursday, December 5, 2019 at 4:21 PM<br> <b>To: </b>"<a href=3D"mailto:[email protected]" target= = =3D"_blank">[email protected]</a>" <<a href=3D"mailt= o:[email protected]" target=3D"_blank">testdrivendevelopment@= groups.io</a>><br> <b>Subject: </b>Re: [testdrivendevelopment] "bottom-up" TDD and = common behaviors</span><u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <p class=3D"MsoNormal">That raises an interesting general question. <u></u><u></u></p> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">"The technology" is a web framework and i= ts linked database framework.<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">The risk of those changing in a way that breaks a l= ot of old code is pretty small. How much effort should we spend insulating = our code against low-probability events?<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">Isolating my code from Ecto would in effect mean in= venting a *new* interface to a RDBMS. Does it really seem likely that I=E2= =80=99ll do that better than the Ecto designers?<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">P.S. I need to spend some time thinking about how F= P ideas and OO ideas play together. My opinion has been that, leaving aside= inheritance, typical FP languages are not different, in practice, than OO languages. But I wonder if that=E2=80=99s right.<u><= /u><u></u></p> <div> <p class=3D"MsoNormal" style=3D"margin-bottom:12pt"><u></u>=C2=A0<u></u></= p> <blockquote style=3D"margin-top:5pt;margin-bottom:5pt"> <div> <p class=3D"MsoNormal">On Dec 4, 2019, at 12:43 AM, Avi Kessner <<a hre= f=3D"mailto:[email protected]" target=3D"_blank">[email protected]</a>>= ; wrote:<u></u><u></u></p> </div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> <div> <div> <p class=3D"MsoNormal">So this is definitely required behavior and it will= be your own, so it needs to be tested. <u></u><u></u></p> <div> <p class=3D"MsoNormal">On the other hand, it's a very specific impleme= ntation detail which could change when the technology changes and we don= 9;t want that to impact actual behavior related tests about animals.<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">What I would do is make a transformation decorator = and then test sample data to see that it gets transformed correctly.=C2=A0 = If Ecto ever changes, that transformation decorator can do nothing if needed.<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">You basically need a map of fields that can be chan= ged and the transformation needed for that field.<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">A bit more work, but it allows for a change in Ecto= or a change in understanding of Ecto to not impact the main test suite.<u>= </u><u></u></p> </div> </div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> <div> <div> <p class=3D"MsoNormal">On Wed, Dec 4, 2019, 01:50 Brian Marick <<a href= = =3D"mailto:[email protected]" target=3D"_blank">[email protected]</a>&= gt; wrote:<u></u><u></u></p> </div> <blockquote style=3D"border-top:none;border-right:none;border-bottom:none;= border-left:1pt solid rgb(204,204,204);padding:0in 0in 0in 6pt;margin:5pt 0= in 5pt 4.8pt"> <div> <div> <p class=3D"MsoNormal">Yes.<u></u><u></u></p> <div> <p class=3D"MsoNormal" style=3D"margin-bottom:12pt"><u></u>=C2=A0<u></u></= p> <blockquote style=3D"margin-top:5pt;margin-bottom:5pt"> <div> <p class=3D"MsoNormal">On Dec 3, 2019, at 5:31 AM, Avi Kessner <<a href= = =3D"mailto:[email protected]" target=3D"_blank">[email protected]</a>>= ; wrote:<u></u><u></u></p> </div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> <div> <p class=3D"MsoNormal"><span style=3D"font-size:12pt;font-family:Helvetica= ">If I understand correctly, the code here is specifically=C2=A0for doing a= n Ecto transformation, correct? If you decide not to use Ecto the need for this abstraction is removed?</span><u></u><u></u></p> </div> </blockquote> </div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> <div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> </blockquote> </div> </div> </blockquote> </div> <p class=3D"MsoNormal">=C2=A0<u></u><u></u></p> </div> </div> </div> </blockquote> </div> <div> <p class=3D"MsoNormal"><u></u></p> </div> </div> </div> <p></p><p></p></blockquote></div> <div width=3D"1" style=3D"color:white;clear:both">_._,_._,_</div> <hr> Groups.io Links:<p> You receive all messages sent to this group. <p> <a target=3D"_blank" href=3D"https://groups.io/g/testdrivendevelopment/mes= sage/35814">View/Reply Online (#35814)</a> | <a target=3D"_blank" href=3D"mailto:[email protected]?subj= ect=3DRe:%20Re%3A%20%5Btestdrivendevelopment%5D%20%22bottom-up%22%20TDD%20a= nd%20common%20behaviors">Reply To Group</a> | <a target=3D"_blank" href=3D"mailto:[email protected]?subject=3DP= rivate:%20Re:%20Re%3A%20%5Btestdrivendevelopment%5D%20%22bottom-up%22%20TDD= %20and%20common%20behaviors">Reply To Sender</a> | <a target=3D"_blank" href=3D"https://groups.io/mt/64491946/3268755">Mu= te This Topic</a> | <a href=3D"https://groups.io/g/testdrivendevelopment/post">New Topic</a>= <br> <br> <a href=3D"https://groups.io/g/testdrivendevelopment/editsub/3268755">Your= Subscription</a> | <a href=3D"mailto:[email protected]">Contact Group Own= er</a> | <a href=3D"https://groups.io/g/testdrivendevelopment/leave/6156322/7445563= 86/xyzzy">Unsubscribe</a> [[email protected]]<br> <div width=3D"1" style=3D"color:white;clear:both">_._,_._,_</div> --0000000000007d07c3059901aae7--