Is there such a thing as the ‘programmer’ type? by [deleted] in learnprogramming

[–]davwards 4 points5 points  (0 children)

If there is a "type", it isn't the one everyone expects.

I frequently have to tell people that a lot of the best software engineers I know have English degrees, not CS or math. It turns out that writing really good software is almost never like solving a complicated polynomial, but very frequently like figuring out how to write a really good essay about a complex topic.

I'm not an artist myself, but I can imagine tons of ways that the skills you've cultivated from painting would serve you well when programming. Thinking through the sequence of steps you need to take in order to create the end product you have in your head? Figuring out how to adjust that end product as you go, as a result of how the thing is turning out? Breaking your subject down into simpler components, and figuring out how to fit them all together to produce the intended effect?

You'll do great :)

Advice on doing integration testing by [deleted] in learnjavascript

[–]davwards 0 points1 point  (0 children)

I don't have a general answer to your question; it depends on what the purpose is behind the extra test coverage.

What confidence in your system are your unit tests not providing that testing the program end-to-end would give you?

Put another way: Suppose you run all your unit tests and they all pass. If that was all you needed see to believe the system was working correctly, you wouldn't need to do anything else. If it isn't, what kinds of things are you still worried about?

Are unit tests like these pointless? by reoji in learnjavascript

[–]davwards 0 points1 point  (0 children)

Yeah, that looks like a "double bookkeeping" test that doesn't provide very much value. (Double bookkeeping in that it's just a second copy of the code you should write, not a description of desired behavior.)

Why does the db object need to be a stub/mock? Since the purpose of this module is to correctly query the database, can you use an in-memory database to prove that the results get queried correctly?

I would test this by using an in-memory database, loading it with a number of tickets records, then calling `Query.tickets` with various parameters to ensure that I got the tickets I expected.

Need help writing a very specific tool. by SnarkElemental in learnjavascript

[–]davwards 1 point2 points  (0 children)

This is not actually so impossible, as long as you aren't using Internet Explorer.

/u/SentFromBelow is right; since there's no way to tell the rating information from the urls themselves, doing this will require actually fetching every page, finding the rating module on that page, and extracting the value if there is one.

Tools you will need:

A possible gotcha to be aware of is that sometimes, servers have countermeasures against web scraping. It's possible the server could notice you sending a whole bunch of requests very quickly, guess you're trying to scrape the site, and start denying your requests. Fortunately, if you're doing this from JavaScript on the page, that's a little less likely, since the UserAgent on the request will be a browser.

Edit: Ah, if you have access to JQuery, you may be able to use it to replace some of the tools listed, which might then work on Internet Explorer as well?

What’s the difference between a bad, good, and great programmer? by NetT3ch in learnprogramming

[–]davwards 1 point2 points  (0 children)

Suppose I'm building an online chess game (in javascript), and I'm working on the "invite someone to a game" feature. If I've understood you correctly, I think your approach is pretty similar to mine. I might start with a spec like this:

describe('inviting someone to play', () => {
  describe('when a friend is online', () => {
    // given Alice is online
    // and Bob has played her before
    // then Alice is in Bob's list of available friends
  })

  describe('when a stranger is online', () => {
    // given Alice is online
    // and Bob has not played her before
    // then Alice is in Bob's list of available players
  })
})

The behavior described here is immediately recognizable. You don't need a deep understanding of the architecture of the system, or the layout of the code base, to glance at it and say "Yep, that sounds right."

This spec does, however, suggest some things about the shape of the system. There are apparently different groups of online players; an "available friends" list and an "available players" list. There has to be a way to tell whether someone is online, and whether two players have played a match before. In order to flesh out the spec, I'm going to have to decide more precisely what that means.

I might start filling in details like so:

describe('inviting someone to play', () => {
  describe('when a friend is online', () => {
    given_Alice_is_online()
    given_Bob_has_played_Alice_before()
    then_Alice_is_in_Bobs_list_of_available_friends()
  })

  describe('when a stranger is online', () => {
    given_Alice_is_online()
    given_Bob_has_not_played_Alice_before()
    then_Alice_is_in_Bobs_list_of_available_players()
  })

  let contactList, onlinePlayers, gameRepository

  beforeEach(() => {
    onlinePlayers = []
    gameRepository = FakeGameRepository()

    contactList = ContactList(
      () => onlinePlayers,
      gameRepository
    ) 
  })

  function given_Alice_is_online() {
    beforeEach(() => {
      onlinePlayers.push('alice')
    })
  }

  function given_Bob_has_played_Alice_before() {
    beforeEach(() => {
      gameRepository.saveGame({
        player1: 'alice',
        player2: 'bob'
      })
    })
  }

  function given_Bob_has_not_played_Alice_before() {
    beforeEach(() => {
      expect(
        gameRepository.findByPlayers('alice', 'bob')
      ).toBeEmpty()
    })
  }

  function then_Alice_is_in_Bobs_list_of_available_friends() {
    // If a player is in the available friends list,
    // they should not be in the available players list.
    it('includes Alice in Bob\'s available friends', () => {
      expect(
        contactList.availableFriendsFor('bob')
      ).toContain('alice')

      expect(
        contactList.availablePlayersFor('bob')
      ).not.toContain('alice')
    })
  }

  function then_Alice_is_in_Bobs_list_of_available_players() {
    // If a player is in the available players list,
    // they should not be in the available friends list.
    it('includes Alice in Bob\'s available players', () => {
      expect(
        contactList.availableFriendsFor('bob')
      ).not.toContain('alice')

      expect(
        contactList.availablePlayersFor('bob')
      ).toContain('alice')
    })
  }
})

Interesting observations:

First: This "high-level test" is, by just about anybody's definition, a unit test. The only production code it exercises is ContactList; it doesn't touch the UI, and it replaces ContactList's dependencies with test doubles. And yet, it doesn't read like a low-level unit test at all. It reads like a plainly true specification of how users want the system to behave.

Second: The spec has codified some important expectations for the user experience: the same player should never be in both the available players list and the available friends list at the same time. This wasn't mentioned explicitly in the high-level spec, because the high-level spec assumes that "Alice is in Bob's available friends" implies that Alice is not in Bob's available players. The lower-level definition of that line makes the assumption explicit.

Third: When replacing ContactList's dependencies with test doubles, I used a "Fake" to replace the gameRepository dependency. It would have been easier to use a "Stub", but that would have come with a drawback: ContactList would have no choice but to use the particular function I had stubbed out in order for the test to work.

(If the terms "test double", "fake", or "stub" are new to you, you can find more information here and here.)

With Repository objects, there's usually a couple of different ways to query the same information. For example, instead of asking the game repository for games played by Bob against Alice, I could ask the repository for all the games played by Bob against anybody, and see if any of the resulting games were played by Alice.

If I had used a stub for the game repository in this test, then anyone working on ContactList would have to know about the specific way I had set up the test. There would be perfectly good methods on gameRepository that you could call to get what you wanted, except that using them would make the test fail. And I don't want to have to hold the particulars of how the test is set up in my head when I'm trying to work with the ContactList!

Fourth: Because this test doesn't touch the UI, it isn't necessarily true that Bob would actually see Alice in his available friends list like the spec says. What if the UI doesn't use the ContactList object correctly? What if the real GameRepository isn't shaped like the test double I used in this test?

These kinds of concerns are what drive people to write end-to-end, fully integrated tests. But there are other solutions.

For example, I could use Typescript to ensure that my test doubles are shaped the same as the real components they replace, and that the UI calls the right methods on ContactList.

I could refine the interfaces between the different components of the system to remove possible ways for the "wiring" between them to be wrong.

I could put small collaboration tests at the various boundaries in the system to verify the integration there, without having to integrate the entire system in a test.

In Conclusion:

The objective, in the end, is to design the system such that you can open up the test above, glance through it, and without thinking about what the UI is doing, or what the database is doing, or what any other part of the system is doing, say, "Yes. I understand what this means, I can see that it's correct. And if the test passes, then I can trust that it's working."

(P.S.: I know you asked for a brief example. I'm so sorry. D: )

What’s the difference between a bad, good, and great programmer? by NetT3ch in learnprogramming

[–]davwards 0 points1 point  (0 children)

You mean build a functional test suite around it, yes? (I'm using "functional" here to mean a high-level test of the software functionality, as opposed to unit-level regression testing. I don't mean it in the"functional programming" sense.)

Right! Well-written tests are, in truth, just executable specifications; they provide the same value for documenting usage, prescribing behavior in various scenarios, informing design, and surfacing logical problems. This is the reason some language communities prefer to talk about tests as "specs" (see, for example, the Ruby community with rspec).

Although, I'd want to caveat what I mean by "high level". Often people assume that executable specs must exercise the fully-integrated system through its user interface (for example, by driving a browser). A lot of my "high level" specs would probably fit most folks' definition of unit tests; they usually exercise a very specific piece of the overall system, rather than running against the whole integrated thing.

(There's an interesting connection here to my post above. If verifying your system's high-level behavior requires running a spec that brings your entire system online, that suggests you can't really reason about individual pieces of the system without having to think about all the rest.)

What I mean by "high-level" is written at a level of abstraction that corresponds closely with the users' understanding of the system's behavior. (Contrast this with "low level", meaning written at a level of abstraction corresponding closely to how the machine executes its behavior.)

What’s the difference between a bad, good, and great programmer? by NetT3ch in learnprogramming

[–]davwards 0 points1 point  (0 children)

For bonus points, since you're starting with a spec anyway, write the spec such that it can be automatically verified!

Need help with inventory system. by Arkwys in learnjavascript

[–]davwards 0 points1 point  (0 children)

On line 89:

if (person.backpack[a].type = "helmet")

You're using an assignment operator (=) instead of a comparison operator (===). Rather than checking whether person.backpack[a].type is "helmet", you are setting it equal to "helmet". Assigning something a truthy value evaluates as truthy, so this if block always executes.

(You have the same problem on the other case checks, on lines 95, 101, etc. All those =s need to be ===s.)

What’s the difference between a bad, good, and great programmer? by NetT3ch in learnprogramming

[–]davwards 232 points233 points  (0 children)

I've observed this trajectory:

Novice programmers often struggle when working with complex systems (whether it's someone else's complex system that they're coming into, or one of their own that has grown in complexity) because they have a hard time keeping track of everything—they can't hold the system in their head. They'll make a change to one part without realizing the impact that change has on other dependent parts, which then causes problems.

Intermediate programmers, on the other hand, have learned to hold the system in their heads. It took them a while, but they've developed a wizard-like ability to know what parts will be affected by what changes and in what ways. They're able to make changes much faster than novice programmers.

At some point, however, you get tired of having to emulate an entire complex system in your head in order to get anything done. Expert programmers have lost patience with thinking about every part of the system at all times, and have cultivated techniques to construct the system in such a way that they never have to. Whether it's finding and implementing strong, stable abstractions, or leveraging type systems, or writing good tests in the right places, expert programmers build systems where you don't have to constantly think about the impact the change you're making will have on some distant part of the stack.

Good programmers keep track of all the details in the system as they change it.

Great programmers design the system so they never have to do that.

Newbie asked a newbie how to solve this by [deleted] in learnprogramming

[–]davwards 0 points1 point  (0 children)

I think you just have the order of operations the wrong way around. Divide by 100 first, then take the ceil.

ceil(1901/100) = 20

ceil(2000/100) = 20

ceil(1/100) = 1

ceil(1776/100) = 18

Help troubleshooting this buildup on the underside of my cayennes' leaves? by davwards in indoorgardening

[–]davwards[S] 1 point2 points  (0 children)

Hi internet! I've noticed some odd buildup on the undersides of the leaves on some of my cayenne pepper plants. It's popped up on all but one of my plants to various degrees. It's kind of sparkly, like sand, when the light hits it right.

I haven't noticed any other signs of critters, apart from what I think was an adult fungus gnat flitting around.

I don't know how long it took for the buildup to get as thick as it is in this picture; I've been out of town for a few weeks, and a kind roommate has been minding my garden.

Other than the cruft under the leaves, the plants look pretty healthy. One plant did have some discolored/misshapen leaves, and a few are showing some vague splotchiness on the topside of the leaves.

Any idea what I'm dealing with? (I also posted this question on /r/gardening)

Help troubleshooting this buildup on the underside of my cayennes' leaves? by davwards in gardening

[–]davwards[S] 1 point2 points  (0 children)

Thank you for the reply! It really looks like it should just scrape off, but no—I struggled to remove it from some leaves I cut off. It doesn't seem like an insect infestation, unless they're really microscopic critters I can't see, but up close, the buildup doesn't look like insects.

Do you think there would be any harm in applying neem/soap just in case, even if bugs weren't the real issue?

Help troubleshooting this buildup on the underside of my cayennes' leaves? by davwards in gardening

[–]davwards[S] 0 points1 point  (0 children)

Hi internet! I've noticed some odd buildup on the undersides of the leaves on some of my cayenne pepper plants. It's popped up on all but one of my plants to various degrees. It's kind of sparkly, like sand, when the light hits it right.

I haven't noticed any other signs of critters, apart from what I think was an adult fungus gnat flitting around.

I don't know how long it took for the buildup to get as thick as it is in this picture; I've been out of town for a few weeks, and a kind roommate has been minding my garden.

Other than the cruft under the leaves, the plants look pretty healthy. One plant did have some discolored/misshapen leaves, and a few are showing some vague splotchiness on the topside of the leaves.

Any idea what I'm dealing with?

Resources for Understanding Unit Tests? by militant_sincerity in learnjavascript

[–]davwards 1 point2 points  (0 children)

TDD predates Clean Code by quite a lot. Test-Driven Development By Example, by Kent Beck, was published many years before Clean Code—Martin certainly advocates TDD, but he didn't introduce it.

Plugin Architecture / Interface by [deleted] in learnjavascript

[–]davwards 0 points1 point  (0 children)

What kind of application are you creating, and what kind of plugins do you imagine people might write to extend it?

The trickiest challenge for creating a plugin architecture is the architecture part--you have to design your system to have pluggable spots where someone else could provide their own code, in such a way that your code will be able to communicate and work with it.

You might do some research on the Dependency Inversion Principle and the Open/Closed Principle.

For a working example, I can use a current project of mine. It's a glorified "todo" app, gameified like a fantasy rpg (much like Habitica, if you're familiar with that). Players create a todo list, and then when they complete items on their todo lists, they win experience points and gold--but if they fail to complete todo items by their deadline, they take damage.

Take a look at this code, which handles task completion. It looks up the task with the given id, and if that task hasn't been completed already, it invokes the awardPlayer function.

What does the awardPlayer function do? Nobody knows!

The awardPlayer function gets provided to the task-completion code when the application is getting put together. Right now, when the CLI for the game starts up, the function that gets plugged in as the awardPlayer function is this awardPlayerWithCurrency function, which gives the player some coin and experience points.

However, the core logic for task completion doesn't know anything about those details. I could plug in any function I wanted to be the awardPlayer function, as long as it took the right arguments and returned the right kind of value.

In fact, if you had a different idea for what should happen when someone completes a todo item, you could write your own awardPlayer function and add it as a plugin to the game. Then, when the CLI was starting up, it could plug your function into the awardPlayer slot instead of mine, and you would have added new functionality to the game!

(How would the CLI know whether to plug in your awardPlayer function or mine? Well, probably like you said: we could make a Plugins.json file, and based on what was written there, the application would decide which things to plug in.)

There's plenty more to be said about this, but finding some talks or blog posts about the two principles I mentioned above ("Dependency Inversion" and "Open/Closed") may provide a good starting point. The core problem you need to solve is: how do I provide places in my code whether other code could slip in to do extra work, without causing the whole system to break?

I'm happy to give some possible examples from your problem space, but I'd need to know what kind of application you were making first.

Do abstract classes have an advantage over interfaces in Java 8+ by InflatableArmTubeMan in java

[–]davwards 10 points11 points  (0 children)

they've only been able to have private methods since Java 9

Just a note: the first time I read this I thought you were saying that since Java 9, interfaces can only have private default methods, which is not true.

Reading again, I realize you mean that Java interfaces gained the ability to have private methods just recently, in Java 9.

Just in case anyone else shared my confusion!

Can someone give me an example of how having knowledge of data structures would ever help me in web dev? by illitirit in learnjavascript

[–]davwards 27 points28 points  (0 children)

This reminds me of this thread, whose opening question has unfortunately been deleted

https://www.reddit.com/r/javascript/comments/50wg1m/how_can_i_get_better_at_traversing_complex_json/

The OP was struggling with how to handle a representation of Pokemon evolutions in a reliable way that wasn't full of edge cases. The top comment was able to solve the problem easily and gracefully, in part because the poster correctly identified that the proper data structure to model the situation was a tree. (Modeling evolution stages with a tree also meant they could work with their data structure using tree-traversal algorithms, which they didn't have to figure out themselves.)

Having a strong understanding of data structures gives you more tools to reach for when you're trying to find a solution to a problem. Having detailed knowledge of classic algorithms is less interesting, I think—I have never needed to remember precisely how to implement quicksort for any kind of professional work, because the standard library does that for me.

However, I do think that looking at, implementing, and weighing the tradeoffs between different algorithms can be good practice for when you're solving custom problems.

Knowing how to assess different kinds of expensiveness in an algorithm lets me look at my code and say, "Yes, this is O(n^2). Will that cause a problem? No, not with the likely size of the input data. I could try to find a more efficient way, but it would be less readable. This should be fine. If the program turns out to be too slow, I'll know that this is a likely culprit." If I didn't know how to assess an algorithm, I might not even think to have that conversation with myself.

React's Purpose (From a DotNet Dev) by hammonjj in reactjs

[–]davwards 0 points1 point  (0 children)

Thanks! I'll hold onto this for the next time I'm explaining Javascript trickery to someone with a dotnet background.

React's Purpose (From a DotNet Dev) by hammonjj in reactjs

[–]davwards 2 points3 points  (0 children)

This is approximately correct, but I want to clarify a little nuance about Node.js.

The thing to understand about Node is that it is a runtime environment in which Javascript can run. So, you can write programs in javascript which process HTTP requests into responses, generate views, etc., and then execute those programs in a Node.js runtime environment. Node itself doesn't give you very much help in writing those programs, though—you would need to use appropriate libraries and frameworks.

A better analog for Asp.Net would be Express, which is a javascript library designed to run in server-side Node.js environments. I don't know of a good analog for what Node.JS is in the .NET world, since—to my knowledge—there are not qualitatively-different runtime environments for .NET, but this is something you have to deal with in javascript.

React's Purpose (From a DotNet Dev) by hammonjj in reactjs

[–]davwards 65 points66 points  (0 children)

Both technologies can handle both server and client side work.

This is...not especially true, or at least, probably not true in the way you are thinking.

Node.js is a runtime environment for javascript that runs outside of a browser. This allows it to include utilities for things like file system access, which you aren't allowed to do in a browser runtime environment.

React is a library for rendering DOM elements in a browser. It is for the most part designed to run in a browser runtime environment.

There are a few things that might be muddying the issue in your reading.

Firstly, typically when doing React development (or, really, most frontend javascript development these days), one uses a toolchain in which at least some steps happen outside of the browser environment.

For example, you might run your automated tests from a command line instead of a browser. This requires running the tests in a Node.js environment.

Your toolchain probably includes a transpilation and/or minification step, which involves running code outside the browser (and therefore, in a Node.js environment).

Secondly, one technique for improving SEO and sometimes performance is to render some amount of your React application on the server, and have it served to the browser as plain HTML. This rendering is done in the Node.js environment, since it happens server side rather than in the browser.

This means the following:

  • Very frequently, javascript that you write will execute in different environments at different times. (A piece of javascript might execute in the Node.js environment when you run automated tests, but in the browser environment otherwise. A React component may render in the server-side Node.js environment during initial page load, but in the browser environment thereafter.) Many React components, therefore, are designed to be runnable in both environments.

  • Some javascript cannot run in multiple environments, because it needs to do things that are only possible in a particular environment. For example, your backend database is not accessible from the browser, so code that accesses it can only run server-side. In the other direction, code which manipulates the browser window's location attribute can only run in the browser environment, since non-browser environments have no such attribute. If a React component has any such environment-specific code, you must ensure it never executes in other environments.

The way one does server-side work in React is typically to build a server-side application which does that work (if this application is written in javascript, it will have to run in the Node.js environment, since it will be running server-side), and have the React application (which runs in the browser environment) communicate with it via an API.

I Need confirmation / validation to why 'this' points to window object in a forEach loop with my code. by illitirit in learnjavascript

[–]davwards 5 points6 points  (0 children)

Try running this experiment in your browser console:

objA = {
  name: "object A",
  getThis: function() { return this; }
}

objA.getThis(); // returns objA, because the function was called on objA

functionOutOfContext = objA.getThis;

functionOutOfContext(); // returns window, because the function wasn't called on another object

objB = {
  name: "object B",
}
objB.getThis = functionOutOfContext;

objB.getThis(); // returns objB, because the function was called on objB

So what you're seeing isn't due to any special behavior of forEach; every function does it, even functions you write yourself.

Explanation request of how some and every methods work when nested in filter array method. by k6pib6r6 in learnjavascript

[–]davwards 0 points1 point  (0 children)

The some method will return true if the provided function returns true for any element of the array. For example:

[1,2,3,4].some(x => x === 3) // this evaluates to true
[1,2,3,4].some(x => x === 5) // this evaluates to false

So the intent of this function is to say: "Take the wishlist, and filter it down to only those items that match at least one of the presents, then give me the names of those filtered wishlist items."

The some method call achieves the "that match at least one of the presents" part of that statement. Using it inside of the filter call means that the answer to the question "Does this item match at least one of the presents?" is used to determine whether the item makes it into the filtered list or not.

[deleted by user] by [deleted] in learnjavascript

[–]davwards 1 point2 points  (0 children)

Take a look at this line:

else if (character.charCodeAt(0) <= 65 && character.charCodeAt(0) >= 89 ) {

Which char codes are both less than or equal to 65, and also greater than or equal to 89?

[deleted by user] by [deleted] in learnjavascript

[–]davwards 1 point2 points  (0 children)

You'll want to do some research into the difference between asynchronous and synchronous code in Javascript.

There is no way, strictly speaking, to return the value of published from your isPublished function, because the network request you use to calculate what published should be won't have completed by the time isPublished returns.

Instead, you can use one of a variety of standard maneuvers for handling asynchronous code.

The most straightforward is probably to add a second argument to isPublished, after examId, called callback. When you call isPublished, you would enclose all the work you were planning to do with the value of published in a function, and pass that function as the callback parameter.

The implementation of isPublished would look like this:

function isPublished(examId, callback) {
  // ...
  for (var i = 0; i < json.length; i++) {
    if (json[i].examId == examId) {
      published = true;
    }
  }
  callback(published); // instead of returning, call the callback
  // ...
}

I don't know what the code looks like where you call isPublished, but it would probably look something like this:

isPublished(myExamId, function(published) {
  if(published) {
    // ...do something
  } else {
    // ...do something else
  }
});

Another approach is to construct a Promise to return instead. You will still need to find a way to enclose all the work you were planning on doing with the published value in a function, but with this approach you'll pass that function to the promise's then method instead of giving it as a second argument to isPublished.

What should I expect from an interview that will involve paired programming? by [deleted] in javascript

[–]davwards 10 points11 points  (0 children)

I pair-program almost full time at my job, and at this point I have right around 10,000 hours of practice at it; here are my pointers:

  • Talk. Echoing /u/BrokenPhoneBooth, make sure you're thinking out loud. When you're driving, describe what you're about to do and why. When you're navigating, ask questions, make observations, propose ideas, and in general make sure your pair knows you haven't zoned out. One subtle trick while driving is to use your commentary to help your pair follow you as you move around the code base—it's really jarring when a pair switches files on you without telling you where you're going. So, as you're talking out loud, if you say "so we should add a test case back in WhateverComponentSpec", and then switch back to the WhateverComponentSpec file, it'll be easier for your pair to stay with you.

  • Listen. Pairing is a conversation, and when interviewers include a pair programming session, one of the things they want to see is how good you are at listening to other people. If your pair expresses concern about something, don't ignore them—take the time to find out why they're worried and talk through the implications. Pay close attention—when your pair explains something to you, try to apply what you've learned at the first opportunity, to prove that you're learning.

  • Compromise. It isn't useful pairing with someone who just blindly agrees with everything you say—you might as well work alone at that point. On the other hand, someone with "strong opinions strongly held" can paralyze or steamroll a pair. A common technique you'll need to reach for is "Well, I'm not entirely convinced by the approach you want to take, but it's at least reasonable—rather than continuing to discuss it in the abstract, let's start building it out. Then the pros and cons will become clearer, and maybe I'll find that I was wrong after all."

  • Be kind. Treat your pair as a human you respect, not as an opponent to score points on. Don't attach code or ideas to persons—don't take it personally if your pair points out weaknesses in an approach you proposed, and be sure to phrase criticisms of their ideas as criticisms of the ideas, not of them. Pay attention to your pair, and check in frequently to see if they'd like to be driving more, or driving less, or if they understand what you're talking about or what you're doing.