user46709: Consider the following:
#define IN1 9
#define IN2 10

pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);

void LeftMotor(Direction direction) {
  digitalWrite(IN1, direction == Forward ? LOW : HIGH);
  digitalWrite(IN2, direction == Forward ? HIGH : LOW);
}

How can I modify the LeftMotor method to achieve the same result without using digitalWrite?

user13432: 
How can I set up outputs without using digitalWrite?

So this question is actually about the fastest possible implementation of digitalWrite.
As described in other answers this can be achieved by using direct port manipulation. But there are actually libraries (for instance, https://github.com/mikaelpatel/Arduino-GPIO) that does this in a portable way and avoids some of the errors that can occur. The library is 10-100X faster than the Arduino core digital pin functions.
Pins in a MCU are organized in ports. On the AVR there are a set of 8-bit port registers that hold the current pin setting. To change the value of a pin the CPU has to read the register and change the corresponding bit associated with the pin. This has to be done as an atomic operation, i.e. an interrupt may not occur during the update of the port register. 
To allow a very fast update, i.e. one instruction/1-2 clock cycle, the CPU has a set of special instructions. For the AVR there are bit set and clear instructions for the 32 first special registers. On the Arduino Mega some of the pins/ports have higher address special registers and cannot use the special instructions. To make the pin operation atomic explicit interrupt handling must be added. 
Other issues with direct port manipulation is portability. Code written using the AVR io handling cannot be used on SAM (e.g. Arduino Due). There is actually even issues when changing between AVR MCUs. 
In short, a portable faster implementation of digital pin functions is recommended. 
Below is the code written with the GPIO. It is portable and as fast as direct port manipulation. 
#include "GPIO.h"

GPIO<BOARD::D9> IN1;
GPIO<BOARD::D10> IN2;

IN1.output();
IN2.output();

void LeftMotor(Direction direction) {
  IN1 = (direction == Forward ? LOW : HIGH);
  IN2 = (direction == Forward ? HIGH : LOW);
}

or 
void LeftMotor(Direction direction) {
  IN1 = direction != Forward;
  IN2 = direction == Forward;
}

or 
void LeftMotor(Direction direction) {
  if (direction == Forward) {
    IN1.low();
    IN2.high();      
  }
  else {
    IN1.high();
    IN2.low();
  }
}


user490: Setting ports directly is a great way to learn AVR programming. I might recommend this book Make: Avr Programming.
First you need to set the direction of the port in the Data Direction Register as either input or output. If Input, check its state and handle it. Here is a small example.  
#define HIGH 1
#define LOW 0

#define  SWI_PIN PORTB0
#define  BUTTON PORTB4


int main (void)
{
    // set the pin directions
    DDRB |=  (1 << SWI_PIN); // output
    DDRB &= ~(1<<PORTB4); //input
    while(true){

      if ((PINB & (1<<BUTTON)) == 0){ // pin is high! Rising edge
          PORTB &= ~(1<<SWI_PIN); // LOW turn off swi_pin
      }else {
          PORTB |= (1<<SWI_PIN); // HIGH  turn on swi_pin
      }

}


user7508: chrisl provided a very good reference answer. Here I am just adding a
few bits of information about the pin mapping and the pin electrical
states.
Pin mapping
One of the firs things you need when dealing with direct port access is
the mapping between the Arduino pin names and the names of the
microcontroller (MCU) pins as given by the manufacturer. For the Arduino
Nano the mapping is the following:
 Arduino │ MCU
─────────┼─────
   RX0   │ PD0
   TX1   │ PD1
   D2    │ PD2
        ... 
   D7    │ PD7
   D8    │ PB0
        ...
   D13   │ PB5
   A0    │ PC0
        ...
   A5    │ PC5

where “PD0” means “pin number 0 of port D” and so on. Notice that pins
A6 and A7 are not listed here, as they are analog only, with no digital
I/O capability.
The information above can be found on the product page of the board,
under the “Documentation” tab. Alternatively, an image search for
“Arduino <board name> pinout” will find some nice schematics like
the one below:

Pin states
This has already been covered by chrisl's answer in the description of
the DDRx and PORTx registers. Below is a summary table showing the
four available electrical states of the pins, and how they are selected
with the DDR and PORT bits:
 DDR │ PORT │ electrical state │ equation
─────┼──────┼──────────────────┼─────────────────
  0  │   0  │  INPUT (high-Z)  │ I = 0
  0  │   1  │  INPUT_PULLUP    │ V = Vcc − Rpu I
  1  │   0  │  OUTPUT LOW      │ V = 0
  1  │   1  │  OUTPUT HIGH     │ V = Vcc

The provided equations relate the output voltage (V) and the output
current (I) of the pin. Beware that these are just rough approximations,
as:

they neglect the output resistance, which is of the order of
25 Ω
an input pin can have some (sub-µA) leakage current
the pullup resistor is not completely linear
the datasheet only provides weak guaranties, such as a range for the
output voltage, conditioned on the output current being low enough.


user42015: digitalWrite() is just a convenience function to hide away complexity from the user, so that she/he can just use a pin number and a value. This complexity takes some time to execute. If this is too slow for you, you need to go a bit deeper into the rabbit hole and use direct port manipulation:
Inside the microcontroller on the Arduino all the special functions for peripherals and such (digital IO, ADC, Serial(UART), SPI, Timer, ...) are configured via Special Function Registers (SFR). These are specific memory places, that are directly connected to the peripherals. You can configure the whole microcontroller by setting these registers to specific values.
For digital IO you first need to know, that the microcontrollers pins are ordered into groups of max 8 pins. These groups are called Ports. Each available port of the microcontroller gets a character, like PORTB. On the Arduino Nano for example PORTD includes the pins 0 to 7.
For each port we have 3 different SFRs (with the x being the character for the corresponding port), where each bit inside the registers corresponds to one pin:

DDRx controls the direction of the pins. If you set a bit to 1 in there, the corresponding pin is set as output. If you set it to zero, the pin will be an input (which is also called High-Z for high impedance, because a digital input pin has a very high resistance).
PORTx controls the output hardware of the digital pins. If you have set a pin as output (as described above) you can use the corresponding bit in the PORTx register to set it's state. If you write a 1 to the bit, the pin will become HIGH (means, the voltage on the pin will go to the same level as Vcc, the supply voltage of the micrcontroller). If you write a zero, the pin will go to LOW (meaning the same level as ground). The PORTx register has a different function, when you configured a pin as input. In this case, a 1 will turn on the interal pullup resistor of the pin, which pulls the level of the pin to HIGH, when nothing is pulling it down to ground (like a switch for example). A zero disables the pullup.
PINx reflects the current state of the pins. If you configured the pins as input, this is the voltage level, that currently lies at the corresponding pin (about the actual voltage levels, see below). A 1 at a bit means, that the corresponding pin is HIGH, else it is LOW.

You can read all of this in the datasheet of the used microcontroller. The datasheet is a must read (at least the relevant chapters), if you want to control the microcontroller via its registers. In most microcontrollers these registers are named as above. But some microcontrollers might define other names. The corresponding datasheet will list all the registers with rather detailed descriptions.
Now let's take that knowledge into actual code. Here I assume an Arduino Nano, though you can exchange that for most other microcontrollers.
// Configure pin D3 as output
DDRD |= (1 << PD3);
// Configure pin D2 as input
DDRD &= ~(1 << PD2);
// Check, if pin D2 is HIGH
if(PIND & (1 << PD2)){
    // Set pin D3 to HIGH
    PORTD |= (1 << PD3);
} else {
    // Set pin D3 to LOW
    PORTD &= ~(1 << PD3);
}


Excourse on bitwise operators: The code above can only be understood by knowing bitwise operators, which are very important for direct port manipulations. I will break down the operations, that are done there:

First we have PD2 and PD3. These are defines from the Arduino core. They are set to the index of the bit, that corresponds to the named pin. So PD2 is defined as 2, PD3 is defined as 3, PD0 as 0.
1 << PD3: The << operator does a bitwise left shift, which means all bits of the value on the left are shifted to the left by the amount standing on the right of the operator. We shift the value 1 three digits to the left here. In binary that looks like this:
0b00000001 << 3 = 0b00001000

That set bit in the result is exactly at the place, where the bits for pin PD3 will be in the Special Function Registers.
DDRD |= (1 << PD3):  This is the same as doing DDRD = DDRD | (1 << PD3), so the |= operator is just an abbreviation for it. The bitwise OR operator | will unite the bits from both sides. If a bit is set to 1 at either side, the result will also have set this bit to 1. This means, that we can set a bit to 1 with this.
~(1 << PD2): The tilde ~ takes the inversion of the data. Alike above, the value inside the paranthesis can be written as binary value 0b00000100. The inversion will flip all bits to the other value: 0b11111011
DDRD &= ~(1 << PD2): The abbreviation is similar to the above. The bitwise AND operator & will also unite the bits of the values around it, but it will only set the resulting bits to 1, if both of the corresponding bits of the values are also set. Here this results in the third bit (the one for D2) being cleared to zero. All other bits (where you can see a 1 at the right value) are left untouched.
PIND & (1 << PD2): This is similar to the above, but now we don't have an inversion. We are doing PIND & 0b00000100 here. All bits of the result will be set to zero, except for the bit for D2. It will only be zero, if the corresponding bit was zero in PIND. Thus we have isolated the needed bit by this way.

You can also combine the same operations on a single register. Let's say we want to set both D2 and D3 as output. Then we can either write this as two seperate statements
DDRD |= (1 << PD2);
DDRD |= (1 << PD3);

or we can combine them into one statement by connecting them with the bitwise OR
DDRD |= (1 << PD2) | (1 << PD3);


The Arduino documentation also provides a site to explain direct port manipulation. Also again you should take the time to look into the datasheet of your used microcontroller. At first it will seems very difficult, but doing these direct port manipulations is a great way of learning how to use the SFRs, and then you can do all sorts of cool stuff with your microcontroller. So it really is worth it. You don't need to read or understand the whole datasheet at once.


How can I modify the LeftMotor method to achieve the same result without using digitalWrite?

After all this text now to the specific question. On the Nano pin 9 and 10 are PB1 and PB2. You used a conditional inside your digitalWrite() statement, which I will replace by a complete if statement here. So you can use
if(direction == Forward){
    PORTB &= ~(1 << PB1);
    PORTB |= (1 << PB2);
} else {
    PORTB |= (1 << PB1);
    PORTB &= ~(1 << PB2);
}

instead of your two digitalWrite() statements.

46709: <p>Consider the following:</p>

<pre><code>#define IN1 9
#define IN2 10

pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);

void LeftMotor(Direction direction) {
  digitalWrite(IN1, direction == Forward ? LOW : HIGH);
  digitalWrite(IN2, direction == Forward ? HIGH : LOW);
}
</code></pre>

<p>How can I modify the <code>LeftMotor</code> method to achieve the same result without using digitalWrite?</p>
 13432: <blockquote>
  <p>How can I set up outputs without using digitalWrite?</p>
</blockquote>

<p>So this question is actually about the fastest possible implementation of digitalWrite.</p>

<p>As described in other answers this can be achieved by using direct port manipulation. But there are actually libraries (for instance, <a href="https://github.com/mikaelpatel/Arduino-GPIO" rel="nofollow noreferrer">https://github.com/mikaelpatel/Arduino-GPIO</a>) that does this in a portable way and avoids some of the errors that can occur. The library is 10-100X faster than the Arduino core digital pin functions.</p>

<p>Pins in a MCU are organized in ports. On the AVR there are a set of 8-bit port registers that hold the current pin setting. To change the value of a pin the CPU has to read the register and change the corresponding bit associated with the pin. This has to be done as an atomic operation, i.e. an interrupt may not occur during the update of the port register. </p>

<p>To allow a very fast update, i.e. one instruction/1-2 clock cycle, the CPU has a set of special instructions. For the AVR there are bit set and clear instructions for the 32 first special registers. On the Arduino Mega some of the pins/ports have higher address special registers and cannot use the special instructions. To make the pin operation atomic explicit interrupt handling must be added. </p>

<p>Other issues with direct port manipulation is portability. Code written using the AVR io handling cannot be used on SAM (e.g. Arduino Due). There is actually even issues when changing between AVR MCUs. </p>

<p>In short, a portable faster implementation of digital pin functions is recommended. </p>

<p>Below is the code written with the <a href="https://github.com/mikaelpatel/Arduino-GPIO" rel="nofollow noreferrer">GPIO</a>. It is portable and as fast as direct port manipulation. </p>

<pre><code>#include "GPIO.h"

GPIO&lt;BOARD::D9&gt; IN1;
GPIO&lt;BOARD::D10&gt; IN2;

IN1.output();
IN2.output();

void LeftMotor(Direction direction) {
  IN1 = (direction == Forward ? LOW : HIGH);
  IN2 = (direction == Forward ? HIGH : LOW);
}
</code></pre>

<p>or </p>

<pre><code>void LeftMotor(Direction direction) {
  IN1 = direction != Forward;
  IN2 = direction == Forward;
}
</code></pre>

<p>or </p>

<pre><code>void LeftMotor(Direction direction) {
  if (direction == Forward) {
    IN1.low();
    IN2.high();      
  }
  else {
    IN1.high();
    IN2.low();
  }
}
</code></pre>
 490: <p>Setting ports directly is a great way to learn AVR programming. I might recommend this book <a href="https://rads.stackoverflow.com/amzn/click/com/1449355781" rel="nofollow noreferrer" rel="nofollow noreferrer">Make: Avr Programming.</a></p>

<p>First you need to set the direction of the port in the Data Direction Register as either input or output. If Input, check its state and handle it. Here is a small example.  </p>

<pre><code>#define HIGH 1
#define LOW 0

#define  SWI_PIN PORTB0
#define  BUTTON PORTB4


int main (void)
{
    // set the pin directions
    DDRB |=  (1 &lt;&lt; SWI_PIN); // output
    DDRB &amp;= ~(1&lt;&lt;PORTB4); //input
    while(true){

      if ((PINB &amp; (1&lt;&lt;BUTTON)) == 0){ // pin is high! Rising edge
          PORTB &amp;= ~(1&lt;&lt;SWI_PIN); // LOW turn off swi_pin
      }else {
          PORTB |= (1&lt;&lt;SWI_PIN); // HIGH  turn on swi_pin
      }

}
</code></pre>
 7508: <p>chrisl provided a very good reference answer. Here I am just adding a
few bits of information about the pin mapping and the pin electrical
states.</p>

<h2>Pin mapping</h2>

<p>One of the firs things you need when dealing with direct port access is
the mapping between the Arduino pin names and the names of the
microcontroller (MCU) pins as given by the manufacturer. For the Arduino
Nano the mapping is the following:</p>

<pre><code> Arduino │ MCU
─────────┼─────
   RX0   │ PD0
   TX1   │ PD1
   D2    │ PD2
        ... 
   D7    │ PD7
   D8    │ PB0
        ...
   D13   │ PB5
   A0    │ PC0
        ...
   A5    │ PC5
</code></pre>

<p>where “PD0” means “pin number 0 of port D” and so on. Notice that pins
A6 and A7 are not listed here, as they are analog only, with no digital
I/O capability.</p>

<p>The information above can be found on the product page of the board,
under the “Documentation” tab. Alternatively, an image search for
“Arduino &lt;board name&gt; pinout” will find some nice schematics like
the one below:</p>

<p><a href="https://i.stack.imgur.com/pSe2G.png" rel="noreferrer"><img src="https://i.stack.imgur.com/pSe2G.png" alt="Arduino Nano pinout"></a></p>

<h2>Pin states</h2>

<p>This has already been covered by chrisl's answer in the description of
the <code>DDRx</code> and <code>PORTx</code> registers. Below is a summary table showing the
four available electrical states of the pins, and how they are selected
with the DDR and PORT bits:</p>

<pre><code> DDR │ PORT │ electrical state │ equation
─────┼──────┼──────────────────┼─────────────────
  0  │   0  │  INPUT (high-Z)  │ I = 0
  0  │   1  │  INPUT_PULLUP    │ V = Vcc − Rpu I
  1  │   0  │  OUTPUT LOW      │ V = 0
  1  │   1  │  OUTPUT HIGH     │ V = Vcc
</code></pre>

<p>The provided equations relate the output voltage (V) and the output
current (I) of the pin. Beware that these are just rough approximations,
as:</p>

<ul>
<li>they neglect the output resistance, which is of the order of
25&nbsp;Ω</li>
<li>an input pin can have some (sub-µA) leakage current</li>
<li>the pullup resistor is not completely linear</li>
<li>the datasheet only provides weak guaranties, such as a range for the
output voltage, conditioned on the output current being low enough.</li>
</ul>
 42015: <p><code>digitalWrite()</code> is just a convenience function to hide away complexity from the user, so that she/he can just use a pin number and a value. This complexity takes some time to execute. If this is too slow for you, you need to go a bit deeper into the rabbit hole and use direct port manipulation:</p>

<p>Inside the microcontroller on the Arduino all the special functions for peripherals and such (digital IO, ADC, Serial(UART), SPI, Timer, ...) are configured via Special Function Registers (SFR). These are specific memory places, that are directly connected to the peripherals. You can configure the whole microcontroller by setting these registers to specific values.</p>

<p>For digital IO you first need to know, that the microcontrollers pins are ordered into groups of max 8 pins. These groups are called Ports. Each available port of the microcontroller gets a character, like PORTB. On the Arduino Nano for example PORTD includes the pins 0 to 7.</p>

<p>For each port we have 3 different SFRs (with the x being the character for the corresponding port), where each bit inside the registers corresponds to one pin:</p>

<ul>
<li><p><code>DDRx</code> controls the direction of the pins. If you set a bit to 1 in there, the corresponding pin is set as output. If you set it to zero, the pin will be an input (which is also called High-Z for high impedance, because a digital input pin has a very high resistance).</p></li>
<li><p><code>PORTx</code> controls the output hardware of the digital pins. If you have set a pin as output (as described above) you can use the corresponding bit in the <code>PORTx</code> register to set it's state. If you write a 1 to the bit, the pin will become HIGH (means, the voltage on the pin will go to the same level as Vcc, the supply voltage of the micrcontroller). If you write a zero, the pin will go to LOW (meaning the same level as ground). The <code>PORTx</code> register has a different function, when you configured a pin as input. In this case, a 1 will turn on the interal pullup resistor of the pin, which pulls the level of the pin to HIGH, when nothing is pulling it down to ground (like a switch for example). A zero disables the pullup.</p></li>
<li><p><code>PINx</code> reflects the current state of the pins. If you configured the pins as input, this is the voltage level, that currently lies at the corresponding pin (about the actual voltage levels, see below). A 1 at a bit means, that the corresponding pin is HIGH, else it is LOW.</p></li>
</ul>

<p>You can read all of this in the datasheet of the used microcontroller. The datasheet is a must read (at least the relevant chapters), if you want to control the microcontroller via its registers. In most microcontrollers these registers are named as above. But some microcontrollers might define other names. The corresponding datasheet will list all the registers with rather detailed descriptions.</p>

<p>Now let's take that knowledge into actual code. Here I assume an Arduino Nano, though you can exchange that for most other microcontrollers.</p>

<pre><code>// Configure pin D3 as output
DDRD |= (1 &lt;&lt; PD3);
// Configure pin D2 as input
DDRD &amp;= ~(1 &lt;&lt; PD2);
// Check, if pin D2 is HIGH
if(PIND &amp; (1 &lt;&lt; PD2)){
    // Set pin D3 to HIGH
    PORTD |= (1 &lt;&lt; PD3);
} else {
    // Set pin D3 to LOW
    PORTD &amp;= ~(1 &lt;&lt; PD3);
}
</code></pre>

<hr>

<p><strong>Excourse on bitwise operators:</strong> The code above can only be understood by knowing bitwise operators, which are very important for direct port manipulations. I will break down the operations, that are done there:</p>

<ul>
<li><p>First we have <code>PD2</code> and <code>PD3</code>. These are defines from the Arduino core. They are set to the index of the bit, that corresponds to the named pin. So <code>PD2</code> is defined as 2, <code>PD3</code> is defined as 3, <code>PD0</code> as 0.</p></li>
<li><p><code>1 &lt;&lt; PD3</code>: The <code>&lt;&lt;</code> operator does a bitwise left shift, which means all bits of the value on the left are shifted to the left by the amount standing on the right of the operator. We shift the value 1 three digits to the left here. In binary that looks like this:</p>

<pre><code>0b00000001 &lt;&lt; 3 = 0b00001000
</code></pre>

<p>That set bit in the result is exactly at the place, where the bits for pin PD3 will be in the Special Function Registers.</p></li>
<li><p><code>DDRD |= (1 &lt;&lt; PD3)</code>:  This is the same as doing <code>DDRD = DDRD | (1 &lt;&lt; PD3)</code>, so the <code>|=</code> operator is just an abbreviation for it. The bitwise OR operator <code>|</code> will unite the bits from both sides. If a bit is set to 1 at either side, the result will also have set this bit to 1. This means, that we can set a bit to 1 with this.</p></li>
<li><p><code>~(1 &lt;&lt; PD2)</code>: The tilde <code>~</code> takes the inversion of the data. Alike above, the value inside the paranthesis can be written as binary value <code>0b00000100</code>. The inversion will flip all bits to the other value: <code>0b11111011</code></p></li>
<li><p><code>DDRD &amp;= ~(1 &lt;&lt; PD2)</code>: The abbreviation is similar to the above. The bitwise AND operator <code>&amp;</code> will also unite the bits of the values around it, but it will only set the resulting bits to 1, if both of the corresponding bits of the values are also set. Here this results in the third bit (the one for D2) being cleared to zero. All other bits (where you can see a 1 at the right value) are left untouched.</p></li>
<li><p><code>PIND &amp; (1 &lt;&lt; PD2)</code>: This is similar to the above, but now we don't have an inversion. We are doing <code>PIND &amp; 0b00000100</code> here. All bits of the result will be set to zero, except for the bit for D2. It will only be zero, if the corresponding bit was zero in <code>PIND</code>. Thus we have isolated the needed bit by this way.</p></li>
</ul>

<p>You can also combine the same operations on a single register. Let's say we want to set both D2 and D3 as output. Then we can either write this as two seperate statements</p>

<pre><code>DDRD |= (1 &lt;&lt; PD2);
DDRD |= (1 &lt;&lt; PD3);
</code></pre>

<p>or we can combine them into one statement by connecting them with the bitwise OR</p>

<pre><code>DDRD |= (1 &lt;&lt; PD2) | (1 &lt;&lt; PD3);
</code></pre>

<hr>

<p>The <a href="https://www.arduino.cc/en/Reference/PortManipulation" rel="noreferrer">Arduino documentation</a> also provides a site to explain direct port manipulation. Also again you should take the time to look into the datasheet of your used microcontroller. At first it will seems very difficult, but doing these direct port manipulations is a great way of learning how to use the SFRs, and then you can do all sorts of cool stuff with your microcontroller. So it really is worth it. You don't need to read or understand the whole datasheet at once.</p>

<hr>

<blockquote>
  <p>How can I modify the LeftMotor method to achieve the same result without using digitalWrite?</p>
</blockquote>

<p>After all this text now to the specific question. On the Nano pin 9 and 10 are PB1 and PB2. You used a conditional inside your <code>digitalWrite()</code> statement, which I will replace by a complete if statement here. So you can use</p>

<pre><code>if(direction == Forward){
    PORTB &amp;= ~(1 &lt;&lt; PB1);
    PORTB |= (1 &lt;&lt; PB2);
} else {
    PORTB |= (1 &lt;&lt; PB1);
    PORTB &amp;= ~(1 &lt;&lt; PB2);
}
</code></pre>

<p>instead of your two <code>digitalWrite()</code> statements.</p>
