Player FM - Internet Radio Done Right
94 subscribers
Checked 12M ago
اضافه شده در seven سال پیش
محتوای ارائه شده توسط Christoph Neumann and Nate Jones, Christoph Neumann, and Nate Jones. تمام محتوای پادکست شامل قسمتها، گرافیکها و توضیحات پادکست مستقیماً توسط Christoph Neumann and Nate Jones, Christoph Neumann, and Nate Jones یا شریک پلتفرم پادکست آنها آپلود و ارائه میشوند. اگر فکر میکنید شخصی بدون اجازه شما از اثر دارای حق نسخهبرداری شما استفاده میکند، میتوانید روندی که در اینجا شرح داده شده است را دنبال کنید.https://fa.player.fm/legal
Player FM - برنامه پادکست
با برنامه Player FM !
با برنامه Player FM !
Ep 024: You Are Here, but Why?
Manage episode 231229956 series 2463849
محتوای ارائه شده توسط Christoph Neumann and Nate Jones, Christoph Neumann, and Nate Jones. تمام محتوای پادکست شامل قسمتها، گرافیکها و توضیحات پادکست مستقیماً توسط Christoph Neumann and Nate Jones, Christoph Neumann, and Nate Jones یا شریک پلتفرم پادکست آنها آپلود و ارائه میشوند. اگر فکر میکنید شخصی بدون اجازه شما از اثر دارای حق نسخهبرداری شما استفاده میکند، میتوانید روندی که در اینجا شرح داده شده است را دنبال کنید.https://fa.player.fm/legal
Christoph needs to test his logic, but he must pry it from the clutches of side effects.
- Last week we ended up with "imperative mud": lots of nested I/O and logic.
- (01:45) Difficult to test when all the I/O and logic are mixed together.
- Object-oriented programming advocates for "mocking" objects with side-effects
- Mocking reinforces and expands the complexity
- Complexity stems from all the different branches of execution: mainline, exceptions, corner cases, etc.
- With the imperative approach, no way to just "jump" to step 2 and test that in isolation. Have to setup all the mocks to tilt the flow of control in the desired direction.
- The Go language handles the "error flow" problem by making error returns explicit (no exceptions), but that further compounds the branching problem.
- (05:25) A different approach to deal with nesting: "happy path" route
- Mainline of execution is the most common case.
- Any error is thrown which has to be handled out of band.
- "Exceptions are much better at mocking you than you are at mocking them."
- Even more problems with mocking: suppose you want to test exponential backoff
- API handle mock has to fail a couple of times and then succeed.
- Requires a "stateful" mock!
- "You have whole object hierarchies that are only in use for your tests!"
- (07:35) Key observation: imperative programming uses the location of execution as a way of encoding information.
- Code in the first branch of the "if" statement "knows" something different than code in the second branch.
- Position in the flow of control is implicit information
- Change implicit information to explicit information and you can flatten out the code.
- Implicit: "You are here because you did X."
- Explicit: "Separating where I am from what to do next."
- "In an imperative flow, the fact you made it to line 3 means something."
- (09:55) To get out of the problem of nesting, we need to have positive, represented information instead of implicit, contextual information.
- Pattern is: logic, I/O, logic, I/O, logic, I/O, etc.
- Capture each one as a multimethod: a "worker" method and a "decider" method.
- The "worker" method dispatches on a "command", just does one thing, and returns the result.
- "My job is not to question why. My job is but to do or die."
- "I don't know if we need to get into the class struggle."
- The "decider" method takes a command and a result, looks at them, decides what to do next, returns a command.
- (18:50) You can work out all the scenarios, and the logic for each scenario is pure!
- Testing becomes a matter of setting the data
- Steps can be tested independently
- (19:45) A "result" isn't simply spewing back the raw data from the I/O
- Worker picks out the relevant parts and return those
- Use spec or schema to document responses
- Can use
meta
or a nested key (like:raw
) to attach raw data for debugging or the "attempt" log (see Ep 022)
- Logic should operate on well-known fields, but recording raw responses is useful for telling a story later on.
- (22:45) Main flow of execution becomes a simple
loop
+recur
- Dispatch
command
to worker and bindresponse
- Dispatch
command
+response
to decider and bindnew-command
(when new-command (recur new-command))
- Dispatch
- (24:30) A downside of the approach: it can be harder to see cases that are not covered, like an unsupported command or unhandled response
- Once again, unit tests can help ensure coverage for the "deciders".
- (27:30) How to test the worker?
- They don't have any logic except doing the side effect.
- Even "picking" the right values from the data could be factored as a pure function
- Can test with the REPL. Try out the side effect and then leave it alone.
- (29:50) Application testing creates another problem
- What about testing the UI? We want to see changes in the data, but we don't want to actually post for real.
- Great topic for next time.
Message Queue discussion:
- (32:05) Do we post the source code for episodes?
- We post some code in the show notes, but less so for a high-level series.
- Send us links to your code and we'll put them on the website.
Related episodes:
Clojure in this episode:
loop
recur
meta
when
118 قسمت
Manage episode 231229956 series 2463849
محتوای ارائه شده توسط Christoph Neumann and Nate Jones, Christoph Neumann, and Nate Jones. تمام محتوای پادکست شامل قسمتها، گرافیکها و توضیحات پادکست مستقیماً توسط Christoph Neumann and Nate Jones, Christoph Neumann, and Nate Jones یا شریک پلتفرم پادکست آنها آپلود و ارائه میشوند. اگر فکر میکنید شخصی بدون اجازه شما از اثر دارای حق نسخهبرداری شما استفاده میکند، میتوانید روندی که در اینجا شرح داده شده است را دنبال کنید.https://fa.player.fm/legal
Christoph needs to test his logic, but he must pry it from the clutches of side effects.
- Last week we ended up with "imperative mud": lots of nested I/O and logic.
- (01:45) Difficult to test when all the I/O and logic are mixed together.
- Object-oriented programming advocates for "mocking" objects with side-effects
- Mocking reinforces and expands the complexity
- Complexity stems from all the different branches of execution: mainline, exceptions, corner cases, etc.
- With the imperative approach, no way to just "jump" to step 2 and test that in isolation. Have to setup all the mocks to tilt the flow of control in the desired direction.
- The Go language handles the "error flow" problem by making error returns explicit (no exceptions), but that further compounds the branching problem.
- (05:25) A different approach to deal with nesting: "happy path" route
- Mainline of execution is the most common case.
- Any error is thrown which has to be handled out of band.
- "Exceptions are much better at mocking you than you are at mocking them."
- Even more problems with mocking: suppose you want to test exponential backoff
- API handle mock has to fail a couple of times and then succeed.
- Requires a "stateful" mock!
- "You have whole object hierarchies that are only in use for your tests!"
- (07:35) Key observation: imperative programming uses the location of execution as a way of encoding information.
- Code in the first branch of the "if" statement "knows" something different than code in the second branch.
- Position in the flow of control is implicit information
- Change implicit information to explicit information and you can flatten out the code.
- Implicit: "You are here because you did X."
- Explicit: "Separating where I am from what to do next."
- "In an imperative flow, the fact you made it to line 3 means something."
- (09:55) To get out of the problem of nesting, we need to have positive, represented information instead of implicit, contextual information.
- Pattern is: logic, I/O, logic, I/O, logic, I/O, etc.
- Capture each one as a multimethod: a "worker" method and a "decider" method.
- The "worker" method dispatches on a "command", just does one thing, and returns the result.
- "My job is not to question why. My job is but to do or die."
- "I don't know if we need to get into the class struggle."
- The "decider" method takes a command and a result, looks at them, decides what to do next, returns a command.
- (18:50) You can work out all the scenarios, and the logic for each scenario is pure!
- Testing becomes a matter of setting the data
- Steps can be tested independently
- (19:45) A "result" isn't simply spewing back the raw data from the I/O
- Worker picks out the relevant parts and return those
- Use spec or schema to document responses
- Can use
meta
or a nested key (like:raw
) to attach raw data for debugging or the "attempt" log (see Ep 022)
- Logic should operate on well-known fields, but recording raw responses is useful for telling a story later on.
- (22:45) Main flow of execution becomes a simple
loop
+recur
- Dispatch
command
to worker and bindresponse
- Dispatch
command
+response
to decider and bindnew-command
(when new-command (recur new-command))
- Dispatch
- (24:30) A downside of the approach: it can be harder to see cases that are not covered, like an unsupported command or unhandled response
- Once again, unit tests can help ensure coverage for the "deciders".
- (27:30) How to test the worker?
- They don't have any logic except doing the side effect.
- Even "picking" the right values from the data could be factored as a pure function
- Can test with the REPL. Try out the side effect and then leave it alone.
- (29:50) Application testing creates another problem
- What about testing the UI? We want to see changes in the data, but we don't want to actually post for real.
- Great topic for next time.
Message Queue discussion:
- (32:05) Do we post the source code for episodes?
- We post some code in the show notes, but less so for a high-level series.
- Send us links to your code and we'll put them on the website.
Related episodes:
Clojure in this episode:
loop
recur
meta
when
118 قسمت
همه قسمت ها
×به Player FM خوش آمدید!
Player FM در سراسر وب را برای یافتن پادکست های با کیفیت اسکن می کند تا همین الان لذت ببرید. این بهترین برنامه ی پادکست است که در اندروید، آیفون و وب کار می کند. ثبت نام کنید تا اشتراک های شما در بین دستگاه های مختلف همگام سازی شود.