Pairing with Duncan
Pairing with Duncan
  • 166
  • 140 109
Mastering Chat-Oriented Programming with Stephan Janssen
In this episode I’m continuing my chat and pairing with Stephan Janssen, founder of the Devoxx conference empire and author of the Devoxx Genie AI plugin for IntelliJ github.com/devoxx/DevoxxGenieIDEAPlugin
Last week (ua-cam.com/video/NRAe4d7n6_4/v-deo.html) Stephan helped me understand how chatting with a large language model is implemented. Armed with this knowledge, this week we open up the Gilded Rose stock control codebase and attempt to use the Anthropic API to understand something of what it does, and ask the LLM how to remove a now-redundant piece of configuration.
Working with an expert has given me new techniques for chat interactions, techniques that improve my success rate, but at the same time made me realise that I may be asking too much of the current state of the art. Stephan’s enthusiasm is infectious though, and makes me believe that interacting with AI systems will be as much part of a modern programmer’s toolset as becoming expert in an IDE, testing tools, refactoring techniques, and so on.
If you like this episode then please subscribe to make sure you catch the final part of our chat, where we talk about the role of source code and architecture in our brave new world.
In this episode
* 00:01:04 Introducing the codebase
* 00:03:18 Settting the system prompt
* 00:06:38 What files are sent to the prompt and how?
* 00:13:15 Describing the whole project
* 00:14:24 Prime the chat with the Features class
* 00:15:45 Be as explicit as possible
* 00:17:39 Refining the suggestion
* 00:21:24 When we have what we want we can try a patch file
* 00:23:13 We can fix things by hand
* 00:25:32 Ask how-to questions rather than give instructions
* 00:29:08 It can be harder to understand than implement
There is a playlist of AI content - ua-cam.com/play/PL1ssMPpyqociSAO5NlyMEYPL6a9eP5xte.html
And many many more on this codebase - ua-cam.com/play/PL1ssMPpyqocg2D_8mgIbcnQGxCPI2_fpA.html
The codebase is available on GitHub github.com/dmcg/gilded-rose-tdd
If you like this video, you’ll probably like my book Java to Kotlin, A Refactoring Guidebook (java-to-kotlin.dev). It's about far more than just the syntax differences between the languages - it shows how to upgrade your thinking to a more functional style.
Переглядів: 421

Відео

Devoxx Genie AI Deep Dive with Stephan Janssen
Переглядів 38221 годину тому
This week I’ve been lucky enough to talk with Stephan Janssen, founder of the Devoxx conference empire and author of the Devoxx Genie github.com/devoxx/DevoxxGenieIDEAPlugin AI plugin for IntelliJ that we looked at last episode. My experience of what people are now calling Chat Oriented Programming - conversing with a large language model to help us write code - is mixed. I have had some impres...
Introducing the Devoxx Genie AI Plugin for IntelliJ
Переглядів 58014 днів тому
I have to confess that I’m really confused by AI tools for software development. I have found them very useful when asked to do simple tasks that I don’t know how to do - writing Bash loops or FFMPEG command lines - that sort of thing. But for real codebases they can be frustrating, either requiring repeated cajoling to get things right, or just missing the point completely. Mostly I think that...
Pairing with Duncan - the rebrand
Переглядів 61021 день тому
Hello it’s Duncan I’ve been a professional developer for more than 30 years. Some of what I’ve learned in that time is written in books, but much much more is transmitted by working with people in teams, often whilst pair programming. Pair programming is a fantastic technique for spreading knowledge; but I know that we can’t all work in an environment where that is possible, or when it is, with...
AI-Generated Property-Based Fizz-BuzzWords - Now with Dark Mode
Переглядів 37228 днів тому
It was only while I was editing the first video in this series that I realised that the code could overflow its integer counter (after two billion or so rounds) and start counting up with negative numbers. Whilst its unlikely that FizzBuzz overflow could blow up a rocket, the point of kata is to practice our skills in a safe environment, so I’m not going to just shrug this off - we should learn...
This one’s important - Refactoring to Functional Kotlin
Переглядів 832Місяць тому
I know - I said that there would only be one FizzBuzz episode! But then people kept making comments on that episode, and asking me questions, and HTTP benchmarking is still hard, and I just can’t help myself, I like to play with code and talk about it. So today we’ll go back to a blank FizzBuzz slate and use the exercise to look at a really important topic - actions and calculations, or impure ...
Ultimate Kotlin TDD FizzBuzz
Переглядів 724Місяць тому
I’m currently helping a less experienced developer (hi Connor) learn Test Driven Development, and this week we looked at the FizzBuzz kata. FizzBuzz is a really good introduction to TDD. Because there is really no complication to get bogged down in, we can focus on the following the process. 1. Write a test that the production code doesn’t pass. The test should show the smallest useful incremen...
Science with Servers - Benchmarking http4k and ktor
Переглядів 415Місяць тому
To be honest, I’ve been putting off benchmarking the ktor (ktor.io) and http4k (http4k.org) libraries, because measuring software performance is hard, and I’m not sure that it makes good TV. The last time I tried, I ended up seeing errors where connections were being broken or reset if we tried to make requests too fast. We can hardly compare performance of things that aren’t working, so this e...
Implementing Interfaces with Method Maps
Переглядів 699Місяць тому
Kent Beck has been writing recently on the idea of the adjacent possible and software design. The adjacent possible is the technological space that we can reach from where we are now in one hop - we don’t have to develop something intermediate before we can implement something useful. In software, sometimes we add some code and find ourselves expanding the adjacent possible. I think that happen...
Hunt the method - Advanced Kotlin Proxy Magic
Переглядів 4222 місяці тому
Our excursion into creating JVM proxies that allow us to delegate suspend functions to non-suspend functions ran into the buffers of the Java module system last week (ua-cam.com/video/5DHDOn3LttA/v-deo.html). We found that we couldn’t call public methods implemented by private classes in another module. That’s annoying, but it’s the nature of reflective code that we often have to wheedle the JV...
Supercharge your Kotlin with Java Dynamic Proxies
Переглядів 8142 місяці тому
We left the last episode (ua-cam.com/video/PdH-1UGAqBk/v-deo.html) with the realisation that we can’t automagically delegate from an interface of suspend functions to an interface of non-suspend functions. That seems like quite an arcane problem, but the solution is generally very useful. It turns that we can implement interfaces at runtime, running dynamic code to respond to method calls. This...
Refactoring to the Repository Pattern
Переглядів 1,3 тис.2 місяці тому
It never ceases to amaze me how bad I am at predicting the subject of the next week’s video. This week I really did set out to benchmark Ktor (ktor.io/) and http4k ((http4k.org) for endpoints that perform IO, but it very quickly became clear that the data model from the example project wasn’t suitable. It uses Kotlin’s MutableList, but the operations on that interface are not suspend functions,...
Benchmarking Ktor and http4k
Переглядів 6872 місяці тому
This week we return to comparing the http4k (http4k.org) and ktor (ktor.io/) http libraries, specifically looking at throughput in requests per second. I’d like to be able to stay “stay tuned to see which is faster”; but the truth is that, on my laptop at least, both seem to be able to route and process requests faster than the operating system is able to accept them. So instead, stay tuned to ...
Advanced techniques for Kotlin Power Assert
Переглядів 4683 місяці тому
I’m going to fast-follow my last video (ua-cam.com/video/ujxNvC_Q_cA/v-deo.html) on Kotlin Power-Assert (kotlinlang.org/docs/power-assert.html) with another on the same subject, because I’m excited by the technology, and the author Brian Norman has been very helpful on the Kotlin Slack. So, without further ado, let’s hack on Power-Assert a bit more. In this episode 00:02:32 Multi-line values do...
Kotlin Power Assert
Переглядів 8683 місяці тому
My regular viewer will know that I’m a test-driven fanatic. I love to find new ways to make tests more expressive and economic, so I was excited when I saw that there was a lightning talk at KotlinConf on Kotlin Power-assert (kotlinlang.org/docs/power-assert.html). Power-assert is a compiler plugin that enhances the regular Kotlin assert function. It promises to help us understand why a test fa...
Was Betteridge right?
Переглядів 8013 місяці тому
Was Betteridge right?
Duncan is away
Переглядів 3913 місяці тому
Duncan is away
We need to talk about Gradle
Переглядів 2 тис.3 місяці тому
We need to talk about Gradle
Generalising all the things - Expert Kotlin Refactoring
Переглядів 5834 місяці тому
Generalising all the things - Expert Kotlin Refactoring
Ktor vs http4k
Переглядів 1,3 тис.4 місяці тому
Ktor vs http4k
(re)Creating a Ktor DSL
Переглядів 7474 місяці тому
(re)Creating a Ktor DSL
Ktor and Dependency Injection
Переглядів 1,2 тис.4 місяці тому
Ktor and Dependency Injection
Kotlin Coroutines and Loom
Переглядів 1,4 тис.5 місяців тому
Kotlin Coroutines and Loom
Composing Higher Order Functions to Create an http4k API
Переглядів 7325 місяців тому
Composing Higher Order Functions to Create an http4k API
Refactoring to Higher-Order Functions - Creating a declarative API for http4k
Переглядів 7905 місяців тому
Refactoring to Higher-Order Functions - Creating a declarative API for http4k
AI Assistant vs Property-based Tests
Переглядів 4625 місяців тому
AI Assistant vs Property-based Tests
Getting creative with jqwik generators - Advanced property-based testing in Kotlin
Переглядів 4296 місяців тому
Getting creative with jqwik generators - Advanced property-based testing in Kotlin
Property-based testing with jqwik and Kotlin
Переглядів 5946 місяців тому
Property-based testing with jqwik and Kotlin
Refactor Mercilessly? - Bowling Part 8
Переглядів 3546 місяців тому
Refactor Mercilessly? - Bowling Part 8
Simplify your Kotlin by Refactoring Actions to Calculations (Bowling Part 7)
Переглядів 5246 місяців тому
Simplify your Kotlin by Refactoring Actions to Calculations (Bowling Part 7)

КОМЕНТАРІ

  • @camilotorresf1
    @camilotorresf1 2 дні тому

    I don't know if this AI is really usefull. Removing that property was a relatively simple example, just grep for the name of the properties to get the files, then open the file and remove the text. Seems easy enough.

    • @PairingWithDuncan
      @PairingWithDuncan 2 дні тому

      My experience has been that for tasks that I know how to do, AI is a bit frustrating. And I know how to do the majority of tasks in my projects. But others are reporting significant productivity gains, and frustration is often a function of lack of experience, so I’m trying to work through to find the sweet spot.

  • @Onlinepmcourses
    @Onlinepmcourses 2 дні тому

    I say please to LLMs too. It's because we are British and were brought up proper.

  • @IPad-gf8mv
    @IPad-gf8mv 2 дні тому

    Enjoyed it 🎉

  • @vanyazkv
    @vanyazkv 8 днів тому

    Thank you for an informative and entertaining video! I really enjoyed having Dmitry as a co-presenter because it feels like participating in a real-life conversation

    • @PairingWithDuncan
      @PairingWithDuncan 8 днів тому

      I appreciate the feedback. I’m trying to feature more actual pairing on the channel, but in the meantime there are quite a few with Dmitry to enjoy

  • @TimSchraepen
    @TimSchraepen 9 днів тому

    Socrates mentioned! Hype!

  • @Onlinepmcourses
    @Onlinepmcourses 9 днів тому

    What! You tease...

  • @Talaria.School
    @Talaria.School 9 днів тому

    Great tool for IJ. Thanks for promoting.

    • @PairingWithDuncan
      @PairingWithDuncan 9 днів тому

      It's certainly nice to have options, and I've learned a lot by using it.

  • @ulicqueldromal
    @ulicqueldromal 14 днів тому

    Important finding, copying with the small clipboard button keeps the formatting. If you disable the "streaming mode (beta)", some of my code is in code blocks that have their own clipboard button. If that is not the case, you can copy the whole message and remove what you don't need. Either way, the formatting stays. Thanks for the video!

  • @nickbw
    @nickbw 14 днів тому

    This made me laugh (at the underwhelming experience) and glad to see I've not been missing much in the AI coding assistant world

    • @PairingWithDuncan
      @PairingWithDuncan 14 днів тому

      So many people I respect report having such good results that I think I must be doing something wrong. Maybe my coding style, choice of language and libraries is just not conducive to AI assistance, or maybe I’m just not patient enough. I hope Stephan will help me work out which.

  • @AlbertScholtz
    @AlbertScholtz 15 днів тому

    This was much more entertaining than I'd imagined, perhaps because I don't feel so alone for struggling with AI plugins now. The Github Copilot trial version was really good but I can't see myself paying $10+ per month. Anyway, looking forward to next video. Thanks for this.

  • @TimSchraepen
    @TimSchraepen 16 днів тому

    Looking forward to seeing you pair with another belgian! 😅

  • @Onlinepmcourses
    @Onlinepmcourses 16 днів тому

    Nice! Enjoyed this. Looking forward to next week.

    • @PairingWithDuncan
      @PairingWithDuncan 16 днів тому

      Thank you. How is AI affecting project management?

  • @AlbertScholtz
    @AlbertScholtz 22 дні тому

    Awesome! Wishing you all the best for the rebrand Duncan. I've only recently discovered your channel. I love the way you communicate the problems and solutions presented. Keep up the good work! Looking forward to what is coming next.

    • @PairingWithDuncan
      @PairingWithDuncan 22 дні тому

      Thanks for the encouragement - it’s great to hear when people like what I do.

  • @azmo_
    @azmo_ 23 дні тому

    one of my top three programming content creators ♥

  • @TimSchraepen
    @TimSchraepen 23 дні тому

    HYPE! Love the “Pairing with Duncan” name

  • @GReeDi0N
    @GReeDi0N 23 дні тому

    I'm excited to see what's comming next !!

    • @PairingWithDuncan
      @PairingWithDuncan 22 дні тому

      I don’t plan to change the formula, just the branding. But, sneak peak, next week will be looking at the Devoxx Genie AI plug-in

  • @OlivierCatteau
    @OlivierCatteau 23 дні тому

    I’m working on a large project in Kotlin where I’m required to do major refactoring, and I want to thank you because I’ve learned so much from watching your videos every week. I can’t wait to see the next ones! 👏

  • @nixoncode
    @nixoncode 23 дні тому

    Excited! what are humans if not adaptable

  • @selocan469
    @selocan469 23 дні тому

    Hope I will pass to the laughing stage someday, right now I am in the suffering stage. I feel like java community esthetics force us into unnecessary tediousness for the sake of high configurability. Well, I want code to get results not code to make my code build... not mentioning here the building hell of 3dparties opensource repos. High flexibility always comes with the cost of extra work, one should consider it when designing a build system. I believe this is a cultural issue with Java community. Config files over config files interacting layer over layer and framework over framework. Welcome to build hell.

    • @PairingWithDuncan
      @PairingWithDuncan 23 дні тому

      There seems to be movement, with both Gradle and JetBrains experimenting with more declarative tools, but you have to really want to be a developer to put up with what we have.

  • @Jallallalla
    @Jallallalla 24 дні тому

    What level of experience/confidence with Kotlin should my team have in order to use more advanced techniques like fold?

    • @PairingWithDuncan
      @PairingWithDuncan 23 дні тому

      That’s an excellent question, thank you. Personally I find map, filter and reduce come naturally, but fold not so much. I still think in terms of mutation like we did here in the repeat loop, and then once things are working look to remove the mutation, which often involves a fold. But it has taken me a few years of functional head-scratching to see the patterns. If as a team you work to remove mutations, even of local variables or collections, then both the code and the team will naturally become more functional together.

  • @nixoncode
    @nixoncode 27 днів тому

    I was today years old when I realized I can't write top level functions to test, doesn't matter if you're on kotlin.test or junit

  • @DavidA-fi9jy
    @DavidA-fi9jy 29 днів тому

    From Kotest docs: Not all arbs have edge cases, but the arbs for the most common types do. Here are some examples of edge cases used by some arbs: ints: 0, 1, -1, Int.MAX_VALUE, Int.MIN_VALUE doubles: 0, 1, -1, Double.MAX_VALUE, Double.MIN_VALUE, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN strings: empty string, string of min length, lowest codepoint lists: empty list, list of a single element, list with duplicate elements maps: empty map nullable values: null You might have had better luck with Kotest (and you wouldn't have to struggle with annotations...)

    • @PairingWithDuncan
      @PairingWithDuncan 29 днів тому

      That’s helpful thank you. I still struggle to like Kotest, and changing frameworks just to add property based tests to a codebase is increases the cost of adding them, but I appreciate that many don’t share my opinion. Maybe I should find a way to make a video about it to learn more.

    • @DavidA-fi9jy
      @DavidA-fi9jy 29 днів тому

      @@PairingWithDuncan I'm pretty sure you don't have to adopt all of Kotest just for the property testing... also in Kotest there's Data-driven testing which is also pretty nice when you just need to create a bunch a situations doing the same thing and don't want to have to create a test for each one separately... It's somewhat like a table of inputs and expecteds.

    • @PairingWithDuncan
      @PairingWithDuncan 29 днів тому

      I suppose that the perceived and actual cost of adoption of a technology is different for everyone as their experience is different, as is the perceived and actual benefit of adoption.

  • @DerTroglodyt
    @DerTroglodyt Місяць тому

    Love your content and love the dark mode. If you're having trouble with dark mode you might try one of the even darker styles which have more contrast. I use one of them (Darcular Darker) and will never go back to white background.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thank you! The problem with dark and my eyes at least is not contrast but that the pupils dilate to bring in more light, which means that depth of field is lower, which leads to focusing problems.

    • @DerTroglodyt
      @DerTroglodyt Місяць тому

      @@PairingWithDuncan That's interesting. I never noticed lower depth of field. For me (approaching 60) it's more about bright backgrounds washing out text.

    • @PairingWithDuncan
      @PairingWithDuncan 29 днів тому

      That's interesting! When I find trouble reading I always turn the brightness up - I guess that would make things worse for you.

  • @Jallallalla
    @Jallallalla Місяць тому

    You made functions that with only production code could be private. Bu you made them public because of tests. Would this not be confusing for someone reading the production code - there are functions that are "unnecessary" public? There a mantra: do not test private methods. In what situations (in Kotlin) would you consider it fine to test private functions by making them public?

    • @PairingWithDuncan
      @PairingWithDuncan 29 днів тому

      Thanks for a very interesting question. I don't have any philosophical issues with testing private methods. If I can test everything that I want to test through the public interface I will, but otherwise 1. If the private function might be useful later, helps understand what I'm thinking, and isn't revealing things that I really want to hide, then hey, public is fine 2. I do think twice about making things public for test if I'm publishing public libraries. I don't want to not be able to change things because people have started using them and I can't change their code. 3. Inside a company though I can often change functions and just fix up all the callers, so that again means I can care less. 4. If a function really is an implementation detail so should not be public, but it's still convenient to write tests for it, then 'internal' visbility is great. 5. Sometimes we can improve our designs by listening following a rule of not testing through effectively private or internal functions, but we can also make things more complicated, so taste is required. Does that help?

  • @21Kikoshi
    @21Kikoshi Місяць тому

    I wish your content didnt use a white background for your IDE. It hurts my eyes to watch it. It if was in dark mode I would watch but sorry I just cant.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      The problem is that, with old eyes, I can’t see dark mode!

    • @21Kikoshi
      @21Kikoshi Місяць тому

      @@PairingWithDuncan Haha all good!

    • @razvanfilip3735
      @razvanfilip3735 Місяць тому

      Light theme feels so comfy for me, like reading a book

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      @razvanfilip3735 Curse you - I’ve literally just started recording this week in dark mode to see how it goes!

    • @21Kikoshi
      @21Kikoshi Місяць тому

      @@PairingWithDuncan haha goodluck!

  • @kyay10
    @kyay10 Місяць тому

    Technically the `i is being mutated` at 9:26 is an implementation detail. Kotlin could've implemented for loops over Int ranges as a tail-recursive function and instead of mutating `i`, it would instead call itself but passing a new value of i. Of course, that's inefficient (unless you use the `tailrec` modifier, which will convert it to a loop with mutation anyways)

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Indeed, but at this point I’m trying to point out actions when we have them, and for loops are pretty actiony. I suppose more so in C where we have to write our own ;I++

  • @codeRight
    @codeRight Місяць тому

    Good stuff! I'm trying to learn more about sequences and this has given a lot to chew on. Love your use of the IDE to make changes quickly and safely.

  • @vengateshm2122
    @vengateshm2122 Місяць тому

    A lot can be done with Fizz Buzz. Nice one. Is capturingStdOut captures whatever prints in console?

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thank you, and yes to your question. You can also capture stderr if you want to see error messages.

  • @PaulMichaelReilly
    @PaulMichaelReilly Місяць тому

    Simply excellent work. Must viewing for all newbies.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thank you. I have had some very good teachers over the years and hope to pass on what I learned while humans still do this job.

  • @DavidA-fi9jy
    @DavidA-fi9jy Місяць тому

    I thought that what you're calling "Acceptance tests" is really end-to-end or integration tests which test the wiring, since they don't really cover all the requirements without the unit tests?

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      I’m not going to disagree; but… …I’ve never been on a project where all requirements are tested in acceptance tests. In practice this would just be too painful to run, especially for non-happy path tests where we may need to mock systems in order to show the behaviour. We might if feeling pedantic mark some unit-level tests as showing acceptance, but I’ve never felt the benefit was worth the hassle. And, it’s late here so I’m a bit slow, what requirements are not covered by the unit tests?

    • @DavidA-fi9jy
      @DavidA-fi9jy Місяць тому

      @@PairingWithDuncan from 21..98 aren't covered. But I agree, I've always felt that pinch that I had to write acceptance tests to cover all the requirements, but in the real world, I only ended up ever writing integration and unit tests... changing the definition of acceptance testing was new for me (what you showed in this video...), but I'm really wondering where to draw the line, especially in a real world project where things tend to be MUCH more complex. Also it seems you didn't write all the acceptance criteria in the beginning, is that what you would recommend?

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Ah interesting. Acceptance tests can't possibly cover all cases. Well, I mean, they could in this case, but we don't test that we can create an account with every possible name. We pick examples and say that if it works for these, it works. So to my mind, examples up to 21 cover the space adequately, with perhaps the additional check that there are 100 results. If I had a product owner, or their QA proxy, who wanted to work to define all the edge cases up-front, then writing all the acceptance criteria at the beginning is good. But how we actually implement the test may change as we implement the implementation - this is an area where Cucumber shines as it decouples the acceptance language from the implementation. In practice though I find that the best is the enemy of the good. Write enough acceptance criteria to get moving - the ones that are obvious. As soon as they become harder to dream up, switch into implementation because the understanding of the domain that code brings will lead to more criteria. Some of those (eg the empty case) may not be acceptance tests, because the spec says 100 lines, but lead to better internal quality and communication to future developers about my mental model.

  • @s-williams
    @s-williams Місяць тому

    25:45 Very silly, but you could always make toFizzBuzz an extension function on Number instead of on Int or Long. Then you only need to support one function instead of two: fun Number.toFizzBuzz(): String = when { this.toLong() % 15L == 0L -> "FizzBuzz" this.toLong() % 5L == 0L -> "Buzz" this.toLong() % 3L == 0L -> "Fizz" else -> toString() } And it works on all number types! There must be a way to do it so that all number types are support and you don't have to convert it to a long too... 🤔

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      I don’t think it’s silly, and I wondered about it when I was editing. It might even work out as fast as the long version by the time Hotspot has had a look.

  • @kyay10
    @kyay10 Місяць тому

    What could be interesting is DDD FizzBuzz: Start off by defining your types, gradually refine them, and get to a good general implementation of FizzBuzz that can support other rules

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      You’re tempting me into a series dammit. There’s a property based version in my head too, and a refactor to a list of predicates to phrases.

  • @khurramijaz2
    @khurramijaz2 Місяць тому

    How about adding connection pooling?

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thanks for the suggestion. I assume you mean having the client reuse connections with Keep-Alive? I have been wondering about this, and given that the errors seem to be in making the connection it would have an effect. I suppose that I was trying to gauge how many different clients we can support, not how many requests a smaller number of clients can make.

    • @khurramijaz2
      @khurramijaz2 Місяць тому

      Duncan, indeed. Both clients have options for connection pooling. That would at least eliminate the network factor and allow us to focus on testing the server stack and application logic.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      🤔that’s a persuasive argument. Given that it’s only really differences between Ktor and http4k that I’m interested in, I guess they will not have any clue that requests have been piggybacking on existing connections. Something to investigate for next week thank you.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      So a little digging reveals that okhttp pools connections by default. How that works in practice I'm not sure. I _assume_ that it will create a new connection if it needs to because an existing one is still waiting for a response, but it's hard to tell.

    • @khurramijaz2
      @khurramijaz2 Місяць тому

      @RefactoringDuncan in case of connection pooling open handles limit should not expire.

  • @nixoncode
    @nixoncode Місяць тому

    Real Duncan is much better, Get well soon

  • @Bozacar
    @Bozacar Місяць тому

    Multiplier for lowering the the request count should be lower than one for increasing it. Otherwise request count will oscilate between error state and stable state, without converging to the max throughput.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      I’m not sure it’s that simple, but I do think that it isn’t currently right! The observed behaviour is not simple oscillation, largely I think because other processes can be taking resources and cause errors for a given rate at one time but not another.

  • @nicolafarina1544
    @nicolafarina1544 Місяць тому

    Hi Duncan, I have another doubt: in runLots fun the property startTimems is written. Shouldn't it be an atomicLong? to guard it against multi-thread access corruption? thanks a lot

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thanks for the review; but I don't think that we have problem there. Firstly we only ever initialise the variable, we don't mutate it. And secondly the variables in runLots are only visible to one thread, the one that is running the test. Actually that second is not completely true, as code in the Callables is run on the executor threads, but that code doesn't access startTimeMs. It does mutate the errors list, which is why we have to make that a thread-safe class. I think! With any multi-threaded code I know that I'm only a single logic-failure away from being completely wrong. As it happens I've just refactored that code, removing the retries and simplifying it a lot. Watch this space on Friday!

  • @Olekj
    @Olekj Місяць тому

    Wouldn't there be a bug where if `invoke()` actually returned null, we'd incorrectly throw "No implementation for method $method"?

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Ooh good catch! Reflection is full of these little gotchas. Somewhere in the back of my mind when I was writing the code I was wondering about the implications of Map<K, V?> and how you tell the difference between not there and there but null. I should have listened to that voice.

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      I think this fixes it val invocationHandler = this.getOrElse(method) { error("No implementation for method $method") } ?: error("Bad default logic for method $method") invocationHandler.invoke(args ?: emptyArray<Any>())

    • @Olekj
      @Olekj Місяць тому

      @@PairingWithDuncan sweet! Really enjoying your videos ❤️

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thank you, it’s nice to have somewhere to play and share the joy of it.

  • @erfansn869
    @erfansn869 Місяць тому

    Thanks for this

  • @nicolafarina1544
    @nicolafarina1544 Місяць тому

    Hi Duncan, just out of curiosity: how many cores has your machine? my figures are quite higher, I have an Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz with 8 cores

    • @nicolafarina1544
      @nicolafarina1544 Місяць тому

      also, in my setup fastFun with loom Jetty is consistently slower than the normal ..🤔

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Mine is an M2 MacBook Air. Given the saturation I’m seeing I don’t think that the processor should make a difference, but maybe the cores are an issue. Are you seeing the same behaviour where you get a cascade of errors?

    • @nicolafarina1544
      @nicolafarina1544 Місяць тому

      @@PairingWithDuncan no I had no errors

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      @nicolafarina1544 I really wish I didn’t. I think all bets are off all the time we are getting them. I’m hoping that they go away when I slow down the responses- watch this space.

  • @xxsaifxx2450
    @xxsaifxx2450 Місяць тому

    what a lovely video it's really nice to get inspired from these types of videos... your videos really helping me to develop large projects and making them easier to maintain, thanks to the algorithm for recommending me this video got a single question here about the proxy approach so in testing why we would use proxy object if we were going to test all the functionality of the object is it a temporary approach for this case so we can test some of the functionality and leave the rest later but I would not do that for the sake of seeing a compile error and handling it the way I want

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      Thanks for your kind words. In testing we might use a proxy in place of a production object because it is easier to set up, or doesn’t launch missiles or somesuch - these are mock objects. In a couple of episodes’ time I think we will use a proxy that just slows down requests to the InMemoryCustomers in order to help test throughput. There are lots of places where we might want to augment existing functionality - see the decorator pattern.

  • @nicolafarina1544
    @nicolafarina1544 Місяць тому

    Hi Duncan thanks for the video, where does the handlerFor (at minute 1:28 more or less) fun come from? Is it an helper of yours? thanks

    • @PairingWithDuncan
      @PairingWithDuncan Місяць тому

      You are welcome! handlerFor is developed in the previous couple of episodes - starting at Refactoring to Higher-Order Functions - Creating a declarative API for http4k ua-cam.com/video/I4NRT--Bj3Q/v-deo.html

  • @vanyazkv
    @vanyazkv 2 місяці тому

    Thank you for a great lesson!

  • @erfansn869
    @erfansn869 2 місяці тому

    Well job

  • @Bozacar
    @Bozacar 2 місяці тому

    I'm not yet went through whole video, but couldn't you used getDeclaredMethod instead of calling getMethod on all super classes and interfaces

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      Hmm, good question - it's led me to some experimentation. Is your suggestion that getDeclaredMethod would prevent us from having to trawl the supertypes, or that we should trawl the supertypes, but use getDeclaredMethod on each?

    • @Bozacar
      @Bozacar 2 місяці тому

      @@PairingWithDuncan Former. Check it out, let me know if I was wrong

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      I’m afraid that you are, but I had to check! getDeclaredMethods specifically doesn’t look in supertypes.

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      I could call getDeclaredMethod on each type in the hierarchy, which would avoid getDeclaredMethod looking up the type hierarchy, but I suspect that I’ve accidentally done the right thing.

    • @Bozacar
      @Bozacar 2 місяці тому

      @@PairingWithDuncan not the first time I was wrong 😁

  • @TimSchraepen
    @TimSchraepen 2 місяці тому

    Get well soon good sir!

  • @i-am-the-slime
    @i-am-the-slime 2 місяці тому

    Java has caused so much pain, suffering, and damage to the entire industry. I'd rather be writing COBOL or punch cards.

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      Wow, that’s a bit extreme. Even if you would rather be writing something else, without Java there would be no JetBrains or Kotlin! Personally I find the language itself to be frustrating these days, but the JVM is an amazing technology and often the right tool for the job.

    • @jimmorrison2657
      @jimmorrison2657 2 місяці тому

      I also don't use Java anymore, but it's a bit daft to diss it so much. If it was that bad it wouldn't have been the biggest language in the world for fifteen years. Duncan, how's it going? We used to work together at Sony with Richard Care. Jim Morrison. Great channel by the way.

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      @jimmorrison2657 Wow blast from the past! I was, coincidentally, just chatting with Richard when I saw your message.

    • @jimmorrison2657
      @jimmorrison2657 2 місяці тому

      @@PairingWithDuncan Aha, ok nice one. That's good to hear. All the best!!

  • @DavidWickes
    @DavidWickes 2 місяці тому

    Nice! Inspired an entire afternoon of hacking around with proxy objects. Just wondering why you looked up the method on `this.java.class` rather than directly invoking the method that was passed to the invocation handler? It _seems_ to work the same for the scrappy one I've tested... but maybe I'm missing something?

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      You can get away with the one passed to the invocation handler if your wrapped object implements the interface, but not otherwise?

    • @DavidWickes
      @DavidWickes 2 місяці тому

      @@PairingWithDuncan Right - that makes sense - and because we were faking the structural subtyping you needed to look up the method from one interface into the other interface. Makes sense now!

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      Next week's video shows that sometimes we have to look harder, down the back of the sofa, inside shoes, all sorts of places.

  • @mikegehard6402
    @mikegehard6402 2 місяці тому

    Love the Big Al’s shirt!

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      Thank you. I have a big bike ride planned this summer, so there will be more cycle attire!

    • @mikegehard6402
      @mikegehard6402 2 місяці тому

      @@PairingWithDuncan enjoy! And thank you for these videos. They are a great way to see another developer’s workflow and thought process.

  • @valcron-1000
    @valcron-1000 2 місяці тому

    Unfortunately I don't think there is a way to abstract over suspend and non suspend methods: once you go `suspend` then everything needs to `suspend`. I worked on a codebase some time ago that dealt with this and we just decided to always make interfaces suspend since once an implementation needs it then you're screwed. I guess this is the famous "function coloring" problem.

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      I think you’re right, and I’ve heard of other codebases with the same policy. Which is a real shame, because suspend functions are definitely harder to test and I assume less efficient to call. I wonder if, if they had their time again, the language designers would have made suspend a context, with special compiler handling, but at least passing the hidden CoroutineContext that way. Is there not a refactor to propagate suspend up the call hierarchy when you find you need it?

    • @valcron-1000
      @valcron-1000 2 місяці тому

      @@PairingWithDuncan I don't think passing the context would be enough since suspend functions are either compiled to a state machine or to continuations (I work mostly with C# where state machines are used, not sure about Kotlin). In C#, once you find something `async` you either force it to be sync (losing the benefits of async in the first place), our you need to propagate the async all the way to `main`. In my experience the best thing is to just start with `async`/`suspend` from main and move on. In languages like Scala or Haskell you can abstract this away since you have access to "generics of generics" (aka higher kinded types), allowing you to write interfaces where the methods/functions are parametrized over some "context" (ex. `fun foo(s: String) -> m Int`, where `m` can be a sync/async context)

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      Kotlin compiles suspend to a state machine too, that’s the special compiler handling that would have to come with the context. As I understand it, that means that every invocation of a suspend function from a suspend function requires the extra code, which means that we pay a performance and code size price. Kotlin’s context receivers, (soon, irritatingly, to be context parameters) will allow us to pass the async context kind of implicitly, but given the state machine issue, that doesn’t really help to generalise the calling, as you say.

    • @garethrowlands
      @garethrowlands 13 днів тому

      I agree Kotlin has no way to abstract over function 'coloring'. In my mind, this is a good argument for http4k over ktor. Ktor is more complicated than http4k but in most cases there's no practical benefit.

  • @SampatB-n2e
    @SampatB-n2e 2 місяці тому

    Could share the GitRepo Link for this benchmarking snippets

    • @PairingWithDuncan
      @PairingWithDuncan 2 місяці тому

      Certainly - its github.com/dmcg/ktor-documentation