[Dev Tip] Event Sourcing

Capture all changes to an application state as a sequence of events.

 12 December 2005

This is part of the Further Enterprise Application Architecture development writing that I was doing in the mid 2000’s. Sadly too many other things have claimed my attention since, so I haven’t had time to work on them further, nor do I see much time in the foreseeable future. As such this material is very much in draft form and I won’t be doing any corrections or updates until I’m able to find time to work on it again.

We can query an application’s state to find out the current state of the world, and this answers many questions. However there are times when we don’t just want to see where we are, we also want to know how we got there.

Event Sourcing ensures that all changes to application state are stored as a sequence of events. Not just can we query these events, we can also use the event log to reconstruct past states, and as a foundation to automatically adjust the state to cope with retroactive changes.

How it Works

The fundamental idea of Event Sourcing is that of ensuring every change to the state of an application is captured in an event object, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself.

Let’s consider a simple example to do with shipping notifications. In this example we have many ships on the high seas, and we need to know where they are. A simple way to do this is to have a tracking application with methods to allow us to tell when a ship arrives or leaves at a port.

Figure 1

Figure 1: A simple interface for tracking shipping movements.

In this case when the service is called, it finds the relevant ship and updates its location. The ship objects record the current known state of the ships.

Introducing Event Sourcing adds a step to this process. Now the service creates an event object to record the change and processes it to update the ship.

Figure 2

Figure 2: Using an event to capture the change.

Looking at just the processing, this is just an unnecessary level of indirection. The interesting difference is when we look at what persists in the application after a few changes. Let’s imagine some simple changes:

  • The Ship ‘King Roy’ departs San Francisco
  • The Ship ‘Prince Trevor’ arrives at Los Angeles
  • The Ship ‘King Roy’ arrives in Hong Kong

With the basic service, we see just the final state captured by the ship objects. I’ll refer to this as the application state.

Figure 3

Figure 3: State after a few movements tracked by simple tracker.

With Event Sourcing we also capture each event. If we are using a persistent store the events will be persisted just the same as the ship objects are. I find it useful to say that we are persisting two different things an application state and an event log.

Figure 4

Figure 4: State after a few movements tracked by event sourced tracker.

The most obvious thing we’ve gained by using Event Sourcing is that we now have a log of all the changes. Not just can we see where each ship is, we can see where it’s been. However this is a small gain. We could also do this by keeping a history of past ports in the ship object, or by writing to a log file whenever a ship moves. Both of these can give us an adequate history.

The key to Event Sourcing is that we guarantee that all changes to the domain objects are initiated by the event objects. This leads to a number of facilities that can be built on top of the event log:

  • Complete Rebuild: We can discard the application state completely and rebuild it by re-running the events from the event log on an empty application.
  • Temporal Query: We can determine the application state at any point in time. Notionally we do this by starting with a blank state and rerunning the events up to a particular time or event. We can take this further by considering multiple time-lines (analogous to branching in a version control system).
  • Event Replay: If we find a past event was incorrect, we can compute the consequences by reversing it and later events and then replaying the new event and later events. (Or indeed by throwing away the application state and replaying all events with the correct event in sequence.) The same technique can handle events received in the wrong sequence – a common problem with systems that communicate with asynchronous messaging.

A common example of an application that uses Event Sourcing is a version control system. Such a system uses temporal queries quite often. Subversion uses complete rebuilds whenever you use dump and restore to move stuff between repository files. I’m not aware of any that do event replay since they are not particularly interested in that information. Enterprise applications that use Event Sourcing are rarer, but I have seen a few applications (or parts of applications) that use it.

Application State Storage

The simplest way to think of using Event Sourcing is to calculate a requested application state by starting from a blank application state and then applying the events to reach the desired state. It’s equally simple to see why this is a slow process, particularly if there are many events.

In many applications it’s more common to request recent application states, if so a faster alternative is to store the current application state and if someone wants the special features that Event Sourcing offers then that additional capability is built on top.

Application states can be stored either in memory or on disk. Since an application state is purely derivable from the event log, you can cache it anywhere you like. A system in use during a working day could be started at the beginning of the day from an overnight snapshot and hold the current application state in memory. Should it crash it replays the events from the overnight store. At the end of the working day a new snapshot can be made of the state. New snapshots can be made at any time in parallel without bringing down the running application.

The official system of record can either be the event logs or the current application state. If the current application state is held in a database, then the event logs may only be there for audit and special processing. Alternatively the event logs can be the official record and databases can be built from them whenever needed.

Structuring the Event Handler Logic

There are a number of choices about where to put the logic for handling events. The primary choice is whether to put the logic in Transaction Scripts or Domain Model. As usual Transaction Scripts are better for simple logic and a Domain Model is better when things get more complicated.

In general I have noticed a tendency to use Transaction Scripts with applications that drive changes through events or commands. Indeed some people believe that this is a necessary way of structuring systems that are driven this way. This is, however, an illusion.

A good way to think of this is that there are two responsibilities involved. Processing domain logic is the business logic that manipulates the application. Processing selection logic is the logic that chooses which chunk of processing domain logic should run depending on the incoming event. You can combine these together, essentially this is the Transaction Script approach, but you can also separate them by putting the processing selection logic in the event processing system, and it calls a method in the domain model that contains the processing domain logic.

Once you’ve made that decision, the next is whether to put the processing selection logic in the event object itself, or have a separate event processor object. The problem with the processor is that it necessarily runs different logic depending on the type of event, which is the kind of type switch that is abhorrent to any good OOer. All things being equal you want the processing selection logic in the event itself, since that’s the thing that varies with the type of event.

Of course all things aren’t always equal. One case where having a separate processor can make sense is when the event object is a DTO which is serialized and de-serialized by some automatic means that prohibits putting code into the event. In this case you need to find selection logic for the event. My inclination would be to avoid this if at all possible, if you can’t then treat the DTO as an hidden data holder for the event and still treat the event as a regular polymorphic object. In this case it’s worth doing something moderately clever to match the serialized event DTOs to the actual events using configuration files or (better) naming conventions.

If there’s no need to reverse events, then then it’s easy to make a Domain Model ignorant of the event log. Reversing logic makes this more tricky since the Domain Model needs to store and retrieve the prior state, which makes it much more handy for the Domain Model to be aware of the event log.

Reversing Events

As well as events playing themselves forwards, it’s also often useful for them to be able to reverse themselves.

Reversal is the most straightforward when the event is cast in the form of a difference. An example of this would be “add $10 to Martin’s account” as opposed to “set Martin’s account to $110”. In the former case I can reverse by just subtracting $10, but in the latter case I don’t have enough information to recreate the past value of the account.

If the input events don’t follow the difference approach, then the event should ensure it stores everything needed for reversal during processing. You can do this by storing the previous values on any value that is changed, or by calculating and storing differences on the event.

This requirement to store has a significant consequence when the processing logic is inside a domain model, since the domain model may alter its internal state in ways which shouldn’t be visible to the event object’s processing. In this case it’s best to design the domain model to be aware of events and to be able to use them in order to store prior values.

It’s worth remembering that all the capabilities of reversing events can be done instead by reverting to a past snapshot and replaying the event stream. As a result reversal is never absolutely needed for functionality. However it may make a big difference to efficiency since you may often be in a position where reversing a few events is much more efficient than using forward play on a lot of events.

External Updates

One of the tricky elements to Event Sourcing is how to deal with external systems that don’t follow this approach (and most don’t). You get problems when you are sending modifier messages to external systems and when you are receiving queries from other systems.

Many of the advantages of Event Sourcing stem from the ability to replay events at will, but if these events cause update messages to be sent to external systems, then things will go wrong because those external systems don’t know the difference between real processing and replays.

To handle this you’ll need to wrap any external systems with a Gateway. This in itself isn’t too onerous since it’s a thoroughly good idea in any case. The gateway has to be a bit more sophisticated so it can deal with any replay processing that the Event Sourcing system is doing.

For rebuilds and temporal queries it’s usually sufficient for the gateways to be able to be disabled during the replay processing. You want to do this in a way that’s invisible to the domain logic. If the domain logic calls PaymentGateway.send it should do so whether or not you are in replay mode. The gateway should handle that distinction by having a reference to the event processor and checking the whether it’s in replay mode before passing the external call off to the outside world.

External updates get more complicated if you are using Retroactive Event see the discussion there for gory details.

Another tactic that you might see with external systems is buffering the external notifications by time. It may be that we don’t need to make the external notification right away, instead we only need to do it at the end of the month. In this case we can reprocess more freely until that time appears. We can deal with this either by having gateways that store external messages till the release date, or triggering the external messages through a notification domain event rather than doing the notification immediately.

External Queries

The primary problem with external queries is that the data that they return has an effect on the results on handling an event. If I ask for an exchange rate on December 5th and replay that event on December 20th, I will need the exchange rate on Dec 5 not the later one.

It may be that the external system can give me past data by asking for a value on a date. If it can, and we trust it to be reliable, then we can use that to ensure consistent replay. It also may be that we are using Event Collaboration, in which case all we have to ensure we retain the history of changes.

If we can’t use those simple plans then we have to do something a bit more involved. One approach is to design the gateway to the external system so that it remembers the responses to its queries and uses them during replay. To be complete this means that the response to every external query needs to be remembered. If the external data changes slowly it may be reasonable to only remember changes when values change.

External Interaction

Both queries and updates to external systems cause a lot of complication with Event Sourcing. You get the worst of both with interactions that involve both. Such an interaction might be a an external call that both returns a result (a query) but also causes a state change to the external system, such as submitting an order for delivery that return delivery information on that order.

Code Changes

So this discussion has made the assumption that the application processing the events stays the same. Clearly that’s not going to be the case. Events handle changes to data, what about changes to code?

We can think as three broad kinds of code changes here: new features, defect fixes, and temporal logic.

New features essentially add new capabilities to the system but don’t invalidate things that happened before. These can be added pretty freely at any time. If you want to take advantage of the new features with old events you can just reprocess the events and the new results pop up.

When reprocessing with new features you’ll usually want the external gateways turned off, which is the normal case. The exception is when the new features involve these gateways. Even then you may not want to notify for past events, if you do you’ll need to put some special handling in for the first reprocess of the old events. It’ll be kludgey, but you’ll only have to do it once.

Bug fixes occur when you look at past processing and realize it was incorrect. For internal stuff this is really easy to fix, all you need to do is make the fix and reprocess the events. Your application state is now fixed to what it should have been. For many situations this is really rather nice.

Again external gateways bring the complexity. Essentially the gateways need to track the difference between what happened with the bug, and what happens without it. The idea is similar to what needs to happen with Retroactive Events. Indeed if there’s a lot of reprocessing to consider it would be worth actually using the Retroactive Event mechanism to replace an event with itself, although to do that you’ll need to ensure the event can correctly reverse the buggy event as well as the correct one.

The third case is where the logic itself changes over time, a rule along the lines of “charge $10 before November 18 and $15 afterwords”. This kind of stuff needs to actually go into the domain model itself. The domain model should be able to run events at any time with the correct rules for the event processing. You can do this with conditional logic, but this will get messy if you have much temporal logic. The better route is to hook strategy objects into a Temporal Property: something like chargingRules.get(aDate).process(anEvent). Take a look at Agreement Dispatcher for this kind of style.

There is potentially an overlap between dealing with bugs and temporal logic when old events need to be processed using the the buggy code. This may lead into bi-temporal behavior: “reverse this event according to the rules for Aug 1 that we had on Oct 1 and replace it according to the rules for Aug 1 that we have now”. Clearly this stuff can get very messy, don’t go down this path unless you really need to.

Some of these issues can be handled by putting the code in the data. Using Adaptive Object Models that figure out the processing using configurations of objects is one way to do this. Another might be embed scripts into your data using some directly executable language that doesn’t require compilation – embedding JRuby into a Java app for example. Of course the danger here is keeping under proper configuration control. I would be inclined to do it by ensuring any change to the processing scripts was handled in the same way as any other update – through an event. (Although by now I’m certainly drifting away from observation to speculation.)

Events and Accounts

I’ve seen some particularly strong examples of Event Sourcing (and consequent patterns) in the context of accounting systems. The two have a very good synergy between them, both in their requirements (audit is very important for accounting systems) and in their implementation. A key factor here is that you can arrange things so that all the accounting consequences of a Domain Event are the creation of Accounting Entrys and link these entries to the original event. This gives you a very good basis for tracking changes, reversal, and the like. In particular it simplified the various adjustment techniques.

Indeed one way of thinking about accounts is that the Accounting Entrys are a log of all of the events that change the value of an Account, so that an Account is itself an example of Event Sourcing.

When to Use It

Packaging up every change to an application as an event is an interface style that not everyone is comfortable with, and many find to be awkward. As a result it’s not a natural choice and to use it means that you expect to get some form of return.

One obvious form of return is that it’s easy to serialize the events to make an Audit Log.Such an audit trail is useful for audit, no shocks there, but also has other usages. I chatted with someone who got their online accounts into an awkward state and phoned in for help. He was impressed that the helper was able to tell him exactly what he did and thus was able to figure out how to fix it. To provide such a capability means exposing the audit trail to the support group so they can walk through a user’s interaction. While Event Sourcing is a good way of doing this, you could also do this with more regular logging mechanisms, and that way not have to deal with the odd interface.

Another use for this kind of complete Audit Log is to help with debugging. Of course, it’s old hat to use log files for debugging production problems. But Event Sourcing can go further, allowing you to create a test environment and replay the events into the test environment to see exactly what happend, with the ability to stop, rewind, and replay just like you can when executing tests in a debugger. This can be particularly valuable to do parallel testing before putting an upgrade into production. You can replay the actual events in your test system and test that you get the answers you expect.

Event Sourcing is the foundation for Parallel Models or Retroactive Events. If you want to use either of those patterns you will need to use Event Sourcing first. Indeed this goes to the extent that it’s very hard to retrofit these patterns onto a system that wasn’t built with Event Sourcing. Thus if you think there’s a reasonable chance that the system will need these patterns later it’s wise to build Event Sourcing now. This does seem to be one of those cases where it isn’t wise to leave this decision to later refactoring.

Event Sourcing also raises some possibilities for your overall architecture, particularly if you are looking for something that is very scalable. There is a fair amount of interest in ‘event-driven architecture’ these days. This term covers a fair range of ideas, but most of centers around systems communicating through event messages. Such systems can operate in a very loosely coupled parallel style which provides excellent horizontal scalability and resilience to systems failure.

An example of this would be a system with lots of readers and a few writers. Using Event Sourcing this could be delivered as a cluster of systems with in-memory databases, kept up to date with each other through a stream of events. If updates are needed, they can be routed to a single master system (or a tighter cluster of servers around a single database or message queue) which applies the updates to the system of record and then broadcasts the resulting events to the wider cluster of readers. Even when the system of record is the application state in a database this could be a very appealing structure. If the system of record is the event log, there is are plenty of options for very high performance since the event log is a purely additive structure that requires minimal locking.

Such an architecture isn’t flawless, of course. The reader systems are liable to be out of sync with the master (and each other) due to differences in timing with event propagation. However this broad style of architecture is used and I’ve heard almost entirely favorable comment about it.

Using event streams like this also allows new applications to be added easily by tapping into the event streams and populating their own models, which don’t need to be the same for all systems. It’s an approach that fits in very well with a messaging approach to integration.

Example: Tracking Ships (C#)

Here is a very simple example of Event Sourcing to get the basic idea over. For this example I’m deliberately being ultra-simple to act as a starting point – then I’ll use further examples to explore some of the more complicated issues.

The domain model is a simple one of ships that carry cargo and move between ports.

Figure 5

There are four kinds of events that affect the model:

  • Arrival: ship arrives at a port
  • Departure: ship leaves a port
  • Load: cargo is loaded on a ship
  • Unload: cargo is unloaded from a ship

Let’s take a simple example of moving a ship around.

class Tester…

  Ship kr;
  Port sfo, la, yyv;
  Cargo refact;
  EventProcessor eProc;

  [SetUp]
  public void SetUp() {
    eProc = new EventProcessor(); 
    refact = new Cargo ("Refactoring");
    kr = new Ship("King Roy");
    sfo = new Port("San Francisco", Country.US);
    la = new Port("Los Angeles", Country.US);
    yyv = new Port("Vancouver", Country.CANADA) ;
  }
[Test]
public void ArrivalSetsShipsLocation() {
  ArrivalEvent ev = new ArrivalEvent(new DateTime(2005,11,1), sfo, kr);
  eProc.Process(ev);
  Assert.AreEqual(sfo, kr.Port);
}
[Test]
public void DeparturePutsShipOutToSea() {
  eProc.Process(new ArrivalEvent(new DateTime(2005,10,1), la, kr));
  eProc.Process(new ArrivalEvent(new DateTime(2005,11,1), sfo, kr));
  eProc.Process(new DepartureEvent(new DateTime(2005,11,1), sfo, kr));
  Assert.AreEqual(Port.AT_SEA, kr.Port);    
}

To make these tests work we just need the arrival and departure events. The event processor is very simple.

class EventProcessor…

  IList log = new ArrayList();  
  public void Process(DomainEvent e) {
    e.Process();
    log.Add(e);
  }

Each event has a process method.

class DomainEvent…

  DateTime _recorded, _occurred;
  internal DomainEvent (DateTime occurred) {
    this._occurred = occurred;
    this._recorded = DateTime.Now;
  }
  abstract internal void Process();

The arrival event simply captures the data and has a process method that simply forwards the event to an appropriate domain object.

class DepartureEvent…

  Port _port;
  Ship _ship;
  internal Port Port  {get { return _port; }}
  internal Ship Ship  {get { return _ship; }}
  internal DepartureEvent(DateTime time, Port port, Ship ship) : base (time)  {
    this._port = port;
    this._ship = ship;
  }
  internal override void Process() {
    Ship.HandleDeparture(this);
  }

So here the event just does the processing selection logic. The processing domain logic is done by the ship.

class Ship…

  public Port Port;
  public void HandleDeparture(DepartureEvent ev) {
    Port = Port.AT_SEA;
  }

A departure event just sets the Ship’s port to a Special Case. You’ll notice I’m passing the event into the domain object. There is a choice here about whether the event should pass in just the data the domain object needs for its processing, or pass in the event itself. By passing the event the event doesn’t need to know exactly what data the domain logic needs. If the event gains additional data later, there’s no need to update signatures. The downside of passing the event is that the domain logic is now aware of the event itself.

That simple test just shows how the basic event processing works. Now I’ll show a little domain logic to see how that would work. Our ships are transporting books to satisfy my fantasies of having an entire shipping line to move my books around the world. As I’m you know, it’s very dangerous to send books through Canada, since it’s this runs the risk of the books being contaminated with lots of “eh”. I’ve seen books where nearly every sentence has a eh (longer sentences can get two or three).

So my perfect book shipping system would be able to detect if a cargo had passed through Canada.

class Tester…

  [Test]
  public void VisitingCanadaMarksCargo() {
    eProc.Process(new LoadEvent(new DateTime(2005,11,1), refact, kr));
    eProc.Process(new ArrivalEvent(new DateTime(2005,11,2), yyv, kr));
    eProc.Process(new DepartureEvent(new DateTime(2005,11,3), yyv, kr ));
    eProc.Process(new ArrivalEvent(new DateTime(2005,11,4), sfo, kr));
    eProc.Process(new UnloadEvent(new DateTime(2005,11,5), refact, kr));
    Assert.IsTrue(refact.HasBeenInCanada);
  }

Since the cargo may be moved between ships and offloaded, it’s the cargo that has the responsibility of knowing whether it’s been exposed to these northern dangers. Fortunately the risk only occurs when actually in a port, just being in the waters is safe. So our arrival event has to keep track of this.

class ArrivalEvent…

  Port _port;
  Ship _ship; 
  internal ArrivalEvent (DateTime occurred, Port port, Ship ship) : base (occurred) {
    this._port = port;
    this._ship = ship;
  } 
  internal Port Port {get {return _port;}}
  internal Ship Ship {get{return _ship;}}
  
  internal override void Process() {
    Ship.HandleArrival(this);
  }

Again the handler is the Ship object.

class Ship…

  IList cargo;
  public void HandleArrival (ArrivalEvent ev) {
    Port = ev.Port;
    foreach (Cargo c in cargo) c.HandleArrival(ev);
  }

The ship isn’t responsible for tracking Canadian visits so it passes the arrival notification on to the cargo.

class Cargo…

  public bool HasBeenInCanada = false;
  public void HandleArrival(ArrivalEvent ev) {
    if (Country.CANADA == ev.Port.Country) 
      HasBeenInCanada = true;
  }

Consider the alternative of where the event process method holds the domain logic – it would need to have a lot of knowledge of the domain model as the domain logic gets more complex. In this approach the domain objects pass the event around to relevant objects so they can handle it to do what they need in response.

Example: Updating an External System (C#)

One of the great features of Event Sourcing is that you can reprocess events as much as you like. However if processing events should cause interactions with external systems, then this is a Bad Thing. The best that could happen is they’ll tired of all your Spam events.

An easy way to help deal with this is to ensure that your system calls external systems through gateways that can be configured to ensure that no messages go out unless you are processing an event ‘for real’.

I’ll illustrate this with a simple example using ships and ports (no cargo this time). Let’s say that whenever a ship enters a port it must notify the local customs authority. We can make this happen in the event processing domain logic.

class Port…

  public void HandleArrival (ArrivalEvent ev) {
    ev.Ship.Port = this;
    Registry.CustomsNotificationGateway.Notify(ev.Occurred, ev.Ship, ev.Port);
  }

Notice that this code just invokes the notification on the gateway object, it doesn’t care whether this is a real processing or some kind of replay. The general principle here is that the domain logic should never care about the context of the running of the events.

It’s the gateway’s responsibility to figure out whether to actually send the message on or not. Since this case is pretty simple, it does this simply by having a link to the event processor and checking to see if the processor is active.

class CustomsEventGateway…

  EventProcessor processor;
  public void Notify (DateTime arrivalDate, Ship ship, Port port) {
    if (processor.isActive) 
      SendToCustoms(BuildArrivalMessage(arrivalDate, ship, port));
  }

The event processor simply makes itself active when doing regular processing.

class EventProcessor…

  public void Process(DomainEvent e) {
    isActive = true;
    e.Process();
    isActive = false;
    log.Add(e);
  }

Although this case is very simple, the fundamental principles are the same. Gateways decide whether to send an external message, not the domain logic. The gateways decide this based on information they gather about the context of the processing. In this case a simple boolean state from the processor is enough.

Example: Reversing an Event (C#)

Here we’ll take the shipping example and see how to reverse the events. The critical thing we need for reversal is to ensure that we can accurately calculate the prior state of any object that has changed state due to the event.

A good place to store this prior data is on the event itself, something that works quite well with the example’s approach of passing the event around the domain objects. Since the domain objects have the event to hand, they can easily store information on the event for them.

The load event makes a simple example. The event carries the following source data.

class LoadEvent…

  int _shipCode;
  string _cargoCode;
  internal LoadEvent(DateTime occurred, string cargo, int ship) : base(occurred){
    this._shipCode = ship;
    this._cargoCode = cargo;
  }
  internal Ship Ship {get { return Ship.Find(_shipCode); }}
  internal Cargo Cargo {get { return Cargo.Find(_cargoCode); }}

The processing is handed off to the cargo object, which needs to store the port that was the prior location of the cargo.

class LoadEvent…

  internal override void Process() {
    Cargo.HandleLoad(this);
  }
internal Port priorPort;

class Cargo…

  internal void HandleLoad(LoadEvent ev) {
    ev.priorPort = _port;
    _port = null;
    _ship = ev.Ship;
    _ship.HandleLoad(ev);
  }

To reverse the event we add a reverse method that mirrors the process method, calling a reversal method on the domain object.

class LoadEvent…

  internal override void Reverse() {
    Cargo.ReverseLoad(this);
  }

class Cargo…

  public void ReverseLoad(LoadEvent ev) {
    _ship.ReverseLoad(ev);
    _ship = null;
    _port = ev.priorPort;
  }

In this case the event takes on a bunch of mutable prior data which is part of its processing data. In cases like this, simple fields suffice. Other cases can require a more sophisticated data structure. When the cargo handles an arrival event, it keeps track of whether it’s been in Canada eh. It can do this with a simple boolean field. To store the prior value on the event needs more than a simple field since many cargoes can be affected by an arrival. So in this case I use a map indexed by the cargo.

class Cargo…

  public void HandleArrival(ArrivalEvent ev) {
    ev.priorCargoInCanada[this] = _hasBeenInCanada;
    if ("CA" == ev.Port.Country) 
      _hasBeenInCanada = true;
  }
  private bool _hasBeenInCanada = false;
  public bool HasBeenInCanada {get { return _hasBeenInCanada;}}

class ArrivalEvent…

  internal Port priorPort;
  internal IDictionary priorCargoInCanada = new Hashtable();

Then to reverse:

class Cargo…

  public void ReverseArrival(ArrivalEvent ev) {
    _hasBeenInCanada = (bool) ev.priorCargoInCanada[this];
  }

This example nicely illustrates how the source data on the event and the error handling affects how we do reversal. For the load event we need to store the port that the cargo was at when it was loaded. If the event included this on its source data we wouldn’t have to do this. A bit of extra source data removes the need to add prior data. This doesn’t work everywhere: the arrival event can’t source the prior Canadian state of its cargoes.

What’s deemed correct processing can also make a difference. In this system we have both arrival events and departure events for ships. Assuming all works correctly we should always get these interleaved. Thus a ship could reverse an arrival event by setting its port field to Port.OUT_TO_SEA. What happens when we get two arrival events in succession? To reverse this we need to store the prior port on the ship. Our alternative would be to declare a second arrival without a departure as an error, we don’t need to do this storage.

Example: External Query (C#)

External queries are awkward even for basic Event Sourcing because if you want to rebuild the application state you need to do this using external query responses that were made in the past.

Let’s imagine a case where a ship has to determine the value of its cargoes when it enters a port. This valuation is done by an external service. If a ship enters a port on November 3rd and I process the event immediately, I’ll get the value of that cargo as at November 3rd. If I rebuild my application state on December 5th I’ll want the same value of the cargo, even if its value has changed in the meantime.

For this example I’ll show one way of handling this by keeping a record of external queries and using them to provide values when reprocessing an event. In many ways it’s a similar approach to that you use with an external update – turn the interaction into events at the boundary of the system and use the record of events to remember what happened.

Using a similar style to event handling that I’m using elsewhere in these examples, we pass the event to the domain objects to handle. In this case the cargo initiates the call to the external system and saves the value. (We’ll assume we’re going to actually do something useful with this value, but that’s not relevant to this example.)

class Cargo…

  public void HandleArrival(ArrivalEvent ev) {
    declaredValue = Registry.PricingGateway.GetPrice(this);
  }
  private Money declaredValue;

As is my habit, I encapsulate all external system access through a Gateway that I control. The basic gateway will just translate the call into whatever is needed for the external interaction. To support replaying events I just wrap this with a class that logs these queries.

Figure 6

Figure 6: Wrapping the gateway with a logging gateway to support proper rebuilding from events.

The logging gateway checks each call to see if it has an old request that matches this one, if not it makes a new request.

class LoggedPricingGateway…

  public Money GetPrice(Cargo cargo) {
    GetPriceRequest oldReq = oldRequest(cargo);
    if (null != oldReq) return (Money) oldReq.Result; 
    else return newRequest(cargo);
  }

If the request is a new one, it turns the request into an event object, invokes the external query, and stores it in the log.

class LoggedPricingGateway…

  private Money newRequest(Cargo cargo) {
    GetPriceRequest request = new GetPriceRequest(cargo);
    request.Result = gateway.GetPrice(cargo);
    log.Store(request);
    return (Money) request.Result;
  }
private class GetPriceRequest : QueryEvent {
  private Cargo cargo;
  public GetPriceRequest(Cargo cargo) : base() {
    this.cargo = cargo;
  }

class QueryEvent…

  DomainEvent _eventBeingProcessed;
  Object result;
  public QueryEvent() {
    _eventBeingProcessed = Registry.EventProcessor.CurrentEvent;
  }
  public object Result {
    get { return result; }
    set { result = value; }
  }
  public DomainEvent EventBeingProcessed {
    get { return _eventBeingProcessed; }
  }
}

So to find an old request, it searches its log.

class LoggedPricingGateway…

  private GetPriceRequest oldRequest(Cargo cargo) {
    IList candidates =
      log.FindBy(EventProcessor.CurrentEvent, typeof (GetPriceRequest));
    foreach (GetPriceRequest request in candidates) {
      if (request.Cargo.RegistrationCode == cargo.RegistrationCode)
        return request;
    }
    return null;
  }

The query log is generic, so we can issue a query to get a few items by using the Domain Event that was processed and the type of request. This gives us a small set that needs further checking in a gateway-specific manner.

The log of requests will need to be persisted in the same way as the log of Domain Events is persisted as it’s needed to rebuild the application state.

REF: http://www.martinfowler.com/eaaDev/EventSourcing.html

[Discovery] Đội ngũ công nhân robot đang làm việc bên trong nhà kho khổng lồ của Amazon

dk_113014-333-660x495.

Nếu như những chiếc máy bay drone sẽ giúo Amazon giao hàng trong tương lai thì ngay lúc này, công ty đã sử dụng nhiều robot tiên tiến khác nhằm tự động hóa công tác bốc dỡ, sắp xếp và vận chuyển hàng hóa trong những nhà kho khổng lồ. Trong đoạn video dưới đây, chúng ta sẽ chứng kiến khung cảnh đội ngũ robot Kiva Systems bên trong một nhà kho khổng lồ của Amazon (hãng robot được Amazon mua lại với giá 775 triệu đô la hồi năm 2012)

​Mỗi “công nhân robot” Kiva nặng khoảng 145 kg, chạy dưới sàn nhà kho và có nhiệm vụ di chuyển các kệ hàng (nặng khoảng 340 kg và cao hơn 1 người trưởng thành) một cách trình tự, khoa học và chính xác cho cảm tưởng như đang lạc vào một nhà máy trong phim khoa học viễn tưởng vậy. Con người chỉ cần chất các món đồ lên kệ hàng và việc còn lại sẽ do robot Kiva đảm nhiệm. Tất cả đã tạo nên một khung cảnh hết sức nhộn nhịp và sống động. Amazon cho biết rằng hiện tại, hơn 15.000 robot Kiva đã được sử dụng cho tất cả các trụ sở và nhà kho của hãng trên khắp nước Mỹ.Bình quân mỗi công nhân Kiva sẽ vận chuyển khoảng 700.000 món hàng mỗi ngày và lúc cao điểm, con số này có thể lên tới 1,5 triệu món.

Theo Amazon, việc sử dụng robot thay cho con người để di chuyển hàng trong kho sẽ giúp tiết kiệm được diện tích do không cần phải làm lối đi cho người, từ đó sẽ có thể chứa được lượng kệ hàng nhiều hơn. Đồng thời, việc dùng robot còn giúp giảm thiểu thời gian chết và thực hiện quá trình luân chuyển hàng hóa hiệu quả hơn. Dù đã sử dụng rất nhiều hệ thống robot hiện đại nhưng Amazon cho biết họ vẫn phải dùng nguồn nhân lực rất lớn. Trong năm 2014 này, hãng đã lên kế hoạch tuyển thêm 80.000 nhân viên để trang trải cho các mùa cao điểm mua sắm vốn được dự đoán là còn cao hơn 14% so với năm ngoái.

Thêm một số hình ảnh bên trong nhà kho của Amazon

dk_113014-48.dk_113014-107.dk_113014-199.dk_113014-250.dk_113014-295.dk_113014-301.dk_113014-389.dk_113014-431.

Tham khảo Amazon, Wire, TC

[Discovery] Làm chủ chiếc máy ảnh của bạn – Phần 1

Sau khi sắm được một chiếc máy ảnh, nhất là chiếc DSLR, việc đầu tiên phải làm là tìm hiểu nó, học cách sử dụng nó, hiểu rõ và thao tác thuần thục các nút bấm các vòng xoay trên thân máy, rồi sau đó mới vào điều chỉnh các tuỳ chọn trong menu, thao tác các chức năng, kiểm soát các thông số… Làm chủ chiếc máy mình đang có sẽ giúp người chụp thao tác nhanh nhạy và trở thành phản xạ tự nhiên như người đi xe phản xạ tay ga, chân số chân thắng nhịp nhàng vậy!Camera.Tinhte.vn sẽ chia sẻ lại một loạt các bài từ cơ bản trở đi hầu phục vụ cho các bạn mới làm quen chụp ảnh.

A. BÊN NGOÀI THÂN MÁY

1. Các nút điều khiển cơ bản
1_camera.tinhte.vn.

2_camera.tinhte.vn.

2. Cảm biến ảnh
Từ thuở đầu của nhiếp ảnh, máy ảnh lưu hình ảnh trên tấm kính hoặc tấm phim. Ngày nay, máy ảnh số tái tạo hình ảnh trên tấm cảm biến hình ảnh. Các tấm cảm biến được tạo thành từ hàng triệu photodiode cảm nhận ánh sáng được thiết kế thành một tấm lưới. Mỗi photodiode ghi lại một điểm nhỏ của hình ảnh và tất cả chúng tạo thành bức ảnh. Hiện có hai loại cảm biến ảnh CCD và CMOS, về cơ bản chúng hoạt động như nhau. Kích thước của cảm biến quan trọng hơn số lượng điểm ảnh trên cảm biến.

  • Full frame: Không kể loại “medium format”, bộ cảm biến kích thước lớn nhất thường được gọi là “full frame” và có kích thước bằng tấm phim 35mm (24x36mm).
  • APS-C: Nhiều máy DSLR dùng bộ cảm biến nhỏ hơn, thường được gọi là APS-C – 22x15mm hoặc tương đương khoảng 40% diện tích của bộ cảm biến full frame.
  • Four Thirds System chỉ bằng 26% bộ cảm biến full frame.
  • APS-H như của EOS 1D Mark III bằng 61% full frame.
  • Foveon X3 của Sigma có kích thước bằng 33% full frame.
  • Một máy bỏ túi hay điện thoại có kích thước cảm biến ảnh là 1/2.5″ thì diẹn tích chỉ bằng 3% full frame.
6_camera.tinhte.vn.


3. Ống kính

Ống kính là cụm thấu kính được làm bằng thuỷ tinh, nhựa tổng hợp chất lượng cao mà ánh sáng xuyên qua nó, ánh sáng được hội tụ lại trên bề mặt phim của máy chụp phim hoặc cảm biến ảnh trong máy ảnh số. Có một số máy ảnh ống kính gắn liền cố định với thân máy như các máy du lịch PnS và có thể hoán đổi ống kính trên máy ảnh DSLR. Nhiều ông kính hoán đổi giúp bạn kiểm soát và sáng tạo được nhiều hơn hình ảnh thu nhận được.

Ống kính là con mắt của máy ảnh. Nó sẽ thu gom các tia sáng và rọi chiếu các tia sáng ấy lên kính ngắm hay bề mặt cảm biến để tạo thành hình ảnh. Chất lượng của ống kính quyết định chất lượng của hình ảnh được tạo ra, cho nên ống kính là yếu tố quan trọng nhất trong việc xử lý hình ảnh. Về cơ bản, có 4 nhóm ống kính:

  • Ống kính tiêu chuẩn – standard
  • Ống kính góc rộng – wide angle
  • Ống kính tiêu cự dài – telephoto
  • Ống kính đa tiêu cự – zoom

Xem bài: tìm hiểu ống kính cơ bản
7_camera.tinhte.vn.

4. Các chế độ chụp ảnh
Auto và các chế độ tự động cơ bản
Đây là chế độ dành cho người bắt đầu cầm máy ảnh. Nikon gọi là Auto mode, Canon gọi là Auto Full. Khi sử dụng chế độ này, chiếc DSLR của bạn trở thành như một chiếc PnS tự động các thiết lập phơi sáng, tốc độ màn trập, khẩu độ, tốc độ, độ nhạy sáng ISO. Bạn chỉ việc bấm nửa nút chụp lấy nét và bấm. Trong đó tự động theo mỗi chủ đề: chân dung, macro, phong cảnh, thể thao, chụp đêm.

  • Thể thao hay hành động: Máy ảnh sẽ tự chọn độ nhạy sáng ISO cao và tốc độ màn trập nhanh để bắt được các chuyển động.
  • Phong cảnh: Máy ảnh sẽ tự chọn các khẩu độ ông skinhs nhỏ để tăng chiều sâu cho vùng ảnh rõ.
  • Chân dung: Máy ảnh sẽ mở lớn khẩu độ ống kính làm nhoà hậu cảnh, hoặc có máy ảnh tự động nhận diện khuôn mặt để lấy nét vào đúng khuôn mặt đó.
  • Chụp đêm: Máy ảnh tự chọn tốc độ màn trập chậm, đủ để ghi nhận chi tiết bối cảnh hoặc đèn flash sẽ tự động nháy để rọi sáng chủ đề gần.
  • Macro: Máy ảnh sẽ khống chế vùng canh nét ở khoảng cách gần, khép khẩu độ nhỏ để tăng chiều sâu cho vùng ảnh rõ.

3_camera.tinhte.vn.
P / Program
Nikon gọi là Program AE mode, Canon gọi là Program Shift. Chọn chế độ này, máy sẽ tự động thiết lập tốc độ màn trập và khẩu độ ống kính. Nhưng độ nhạy sáng ISO, bù trừ sáng và các thiết lập khác thì bạn tự thiết lập và kiểm soát. Bạn có thể để ISO thấp nhất để giảm độ nhiễu, và để chế độ P trong trường hợp chụp nhanh không cần phải suy nghĩ tính toán.

A / Av Aperture Priority
Đây là chế độ bán tự động cho phép bạn chủ động chọn khẩu độ (độ f của ống kính) theo ý muốn, và máy tự động chọn tốc độ màn trập cần thiết tương ứng với khẩu độ bạn chọn để đúng sáng. Chế độ này còn được gọi là “ưu tiên khẩu độ”. Ví dụ bạn muốn chụp khẩu độ f/2.8, bạn sẽ chủ động chỉnh khẩu f/2.8, khẩu độ sẽ tự máy chọn với tình trạng ánh sáng hiện tại bạn chụp.

S / Tv / Shutter Priority
Cả Nikon và Canon đều gọi là ưu tiên tốc độ màn trập, nhưng Nikon viết tắt là chữ S, Canon viết tắt là chữ Tv. Chế độ này ngược lại chế độ A / Av trên. Bạn chủ động chọn tốc độ màn trập và máy tự động chọn khẩu độ tương ứng cho đúng sáng. Thường chọn chế độ này khi người chụp muốn duy trì một tốc độ cao để tránh rung lắc và khẩu độ phó mặc cho máy tuỳ chọn tương ứng.

M (Manuel)
Cả hai hãng Nikon & Canon đều viết tắt là M, nhưng Nikon gọi là Manual mode, Canon gọi là Metered manuel. Chế độ này hay gọi là chế độ chụp manual, chỉnh hoàn toàn bằng tay. Bạn sẽ phải chủ động chọn tốc độ màn trập, khẩu độ cho tất cả mọi cú bấm máy. Đặc biệt, ở chế độ này, bạn có thể chụp tốc độ hoàn toàn chủ động Bulb (bấm máy và màn trập mở liên tục đến khi nào thả nút chụp thì màn trập mới đóng lại) dành cho các trường hợp phơi sáng lâu.

Ev (Exposure value)
Các chế độ chụp P, S và A còn có thể tinh chỉnh thêm nữa bằng cách tăng giảm các giá trị EV. Đây là thang độ chia thành nhiều nấc, mỗi nấc tương ứng với một tỷ lệ lộ sáng. Giá trị Ev thường được điều chỉnh bằng vòng xoay hoặc nút bấm.

Một số máy ảnh có chế độ Exposure Bracketing (chụp bù trừ tự động). Khi chụp ở chế độ này, máy ảnh sẽ tự động chụp một loạt 3, 5 hoặc 7 tấm ảnh với các giá trị lộ sáng khác nhau để tăng thêm khả năng có một bức ảnh chụp đúng sáng nhất.

5. Đèn

Máy ảnh du lịch (compact/pns) có đèn gắn cố định trong thân máy được kích hoạt đồng bộ với màn trập máy ảnh, nhưng không thể kiểm soát thời gian và cường độ sáng của đèn. Máy DSLR thì có đèn pop-up (cóc) có thể kiểm soát để đồng bộ với màn trập, cường độ sáng phù hợp với tuỳ cảnh vật.
5_camera.tinhte.vn.

  • Auto flash: Máy ảnh sẽ tự động nháy sáng đèn flash trong điều kiện ánh sáng yếu. Đèn flash sẽ là nguồn sáng chính.
  • Off flash: Không cho đèn tự động nháy sáng. Máy ảnh sẽ tự động nâng độ nhạy sáng ISO lên và chọn các khẩu độ mở rộng nhất để có thể chụp ảnh trong điều kiện nguồn sáng tự nhiên hạn chế.
  • Fill flash: Máy ảnh sẽ tự điều chỉnh để cân bằng nguồn sáng tự nhiên và lượng sáng của đèn flash.
  • Red-eye reduction: Máy ảnh sẽ nháy sáng đèn flash một lần trước khi nháy sáng lần thứ hai để chụp ảnh. Lần sáng trước nhằm làm cho đồng tử trong mắt của người được chụp co lại để giảm hiệu ứng mắt đỏ. Đây là hiệu ứng nhiếp ảnh chứ không phải hiện tượng tồn tại trong tự nhiên.
  • On flash: Đèn sẽ sáng liên tục khi chụp, bất kể là hoàn cảnh ánh sáng nào.


6. Hệ thống ngắm

Kính ngắm chỉ là một bộ phận để xác định khung hình. Hình ảnh qua kính ngắm lúc nào cũng rõ nét. Để trợ giúp cho việc lấy nét, các máy ảnh có thêm một cơ phận dò cự ly được thiết kế chung với kính ngắm. Đó là một cặp lăng kính nhỏ hoặc gương nằm bên trong thân máy ảnh. Một gương mờ đặt cố định mà ta có thể nhìn xuyên qua. Cặp gương hay lăng kính kia sẽ xoay khi ống kính của máy ảnh được điều chỉnh lấy nét, khi hai hình ảnh chồng lên nhau tức là ánh sáng qua ống kính đã được hội tụ vào cùng một khoảng cách.
4_camera.tinhte.vn.


B. CÁC CHẾ ĐỘ ĐO SÁNG

Các thông số về thời chụp đều phụ thuộc vào bốn yếu tố biến đổi:

  • Cường độ ánh sáng hắt vào chủ đề, hay độ sáng của chủ đề phản chiếu tới máy ảnh (hoàn cảnh sáng).
  • Độ nhạy của bộ cảm biến đối với ánh sáng (ISO)
  • Khoảng thời gian cho bộ cảm biến lộ sáng (tốc độ màn trập).
  • Lượng sáng đi vào bộ cảm biến (điều khiển bằng khẩu độ ống kính)

Máy ảnh số có hệ thống đo sáng bên trong giúp chọn lựa tốc độ màn trập, khẩu độ ống kính, độ nhạy sáng phù hợp để bộ cảm biến được lộ sáng đúng. Các hệ thống đo sáng thiết kế chung với máy ảnh đều đo ánh sáng phản chiếu – ánh sáng từ chủ thể hắt về phía máy ảnh – và được nối kết trực tiếp với các bộ phận điều khiển tốc độ và khẩu độ.

Các máy ảnh đo sáng qua ống kính (through the lens – TTL), dựa vào lượng sáng thật sự tạo thành hình ảnh và sẽ tác dụng đến cảm biến. Khi thay đổi ống kính, hoặc gắn thêm kính lọc (filter) vào trước ống kính, hệ thống đo sáng TTL đó tự động điều chỉnh theo sự thay đổi đó.
8_Camera.tinhte.vn.

  • Đo sáng trung tâm (center-weighted average metering): Chế độ đo sáng tập trung ở khu vực chính giữa hơi chệch xuống dưới, kiểu đo sáng thường được gọi là “đo trung bình ưu tiên giữa”, bởi vì các yếu tố quan trọng nhất của mọi bức ảnh thường là nằm ở khu vực này.
  • Chế độ đo sáng ma trận (matrix metering hay multi segment metering): Kính ngắm của máy có hệ thống đo sáng này được chia thành nhiều phần (segment), mỗi phần sẽ đo sáng một khu vực hình ảnh nhất định, máy ảnh sẽ nhận mọi thông số và tính ra độ nhạy, tốc độ, khẩu độ phù hợp với hoàn cảnh sáng.
  • Đo sáng điểm (spot metering): Đo sáng tại một điểm nhỏ, cho thông số rất chính xác. Điểm đo sáng nằm ở giữa tâm kính ngắm, và một số dòng máy ảnh cho phép dịch chuyển vị trí đo sáng điểm này để thuận tiện cho việc bố cục khung hình.

Như ta vẫn nói “nhiếp ảnh là trò chơi với ánh sáng” thì đo sáng là chức năng quan trọng của chiếc máy ảnh (hoặc cầm máy đo sáng bằng tay), vì nó xác định giá trị phơi sáng cho máy ảnh. Chọn chế độ đo sáng sai, đo sáng sai cách sẽ ảnh hưởng đến chất lượng bức ảnh, có thể làm hỏng bức ảnh. Ngược lại, đo sáng đúng, bức ảnh có kết quả tốt.

C. CÂN BẰNG TRẮNG
Mắt người tự động thích ứng rất nhanh với những thay đổi về ánh sáng, nhưng bộ cảm biến ảnh của máy ảnh lại không thể tự động thích ứng chính xác như vậy. Đây là vấn đề chính của màu sắc trong ảnh. Màu sắc của bức ảnh được chụp nhiều khi không giống với màu tự nhiên, và vì vậy máy ảnh số phải cân bằng lại màu sắc theo cách cân bằng trắng (white balance).

White Balance là cân chỉnh ánh sáng theo màu trắng – khái niệm quen thuộc với dân quay video hồi trước. Ánh sáng ban ngày là một nguồn sáng lạnh không màu nhưng nếu trời có mây mù hay ta bước vào bóng râm thì mọi vật thể đều có màu lẫn với sắc xanh. Trong căn phòng thắp đèn vàng dây tóc, ánh sáng ở đó sẽ có sắc đỏ cam ấm áp trong khi ở trong phòng ánh đèn huỳnh quang thì mọi màu sắc pha chút xanh lá cây. Cân bằng trắng là công việc làm cho hình ảnh được chụp có màu sắc trung thực. Máy ảnh số nào cũng có các chế độ White Balance.
9_camera.tinhte.vn.

  • Auto White Balance: tự động cân bằng màu sắc
  • White Balance theo các nhóm nguồn sáng: ngoài trời nắng, dưới mây mù, trong nhà, dưới ánh đèn vàng, dưới ánh đèn huỳnh quang… máy ảnh tự động tuỳ hoàn cảnh thực tế để ghi nhận màu trắng đúng thật.
  • Nhiệt độ K: người dùng tự điều chỉnh các cấp độ cân bằng trắng theo thang độ K.

12_camera.tinhte.vn.
a copy.


“Chiếc máy ảnh là một tấm gương soi có trí nhớ nhưng không biết tư duy”
(Arnold Newman 1918-2006)
Tìm hiểu cơ bản để biết thiết bị mình sử dụng giúp làm chủ nó tốt hơn. Cụ thể là điều chỉnh các vòng xoay, nút bấm hay lựa chọn trong menu phù hợp và nhanh nhạy dần dần như phản xạ tự nhiên, giúp người mới dùng máy ảnh chụp ảnh tốt hơn. Tất cả thao tác ấy giúp người dùng kiểm soát các thông số để đảm bảo ảnh đúng sáng hoặc đúng ý. Các phần sau sẽ tìm hiểu sâu hơn từng chức năng và nguyên lý hoạt động của chiếc máy ảnh.

Các bài viết liên quan có thể bạn cần đọc:

  1. Các yếu tố cơ bản làm chủ máy ảnh
  2. Tìm hiểu cục pin máy ảnh
  3. Các nút điều khiển trên thân máy ảnh P.1
  4. Các nút điều khiển trên thân máy ảnh P.2
  5. Các thông số cơ bản làm chủ máy ảnh: ISO – Tốc độ – Khẩu độ

[Discovery] Làm chủ chiếc máy ảnh của bạn – Phần 2

74150003 copy.tinhte.vn.

Chúng ta đã làm quen với máy ảnh phần 1. Bài này tiếp tục tìm hiểu chiếc máy và ống kính có những cấu trúc thành phần nào và cơ chế hoạt động làm sao. Về cơ bản thì mọi máy ảnh chỉ là một cái hộp kín, không lọt sáng, một đầu có lỗ hở để ánh sáng đi vào, và đầu kia là bộ phận chứa phim hoặc bộ cảm biến ảnh. Nó tạo ra hình ảnh bằng cách tích tụ các tia sáng được phản xạ từ cảnh vật và rọi thành hình ảnh trên bề mặt phim có độ nhạy sáng hoặc trên cảm biến hình ảnh. Các bộ phận cơ bản đó là:

  • Một ống kính: thu nhận ánh sáng.
  • Một hệ thống kính ngắm: để ta nhìn thấy khung ảnh sẽ thu vào.
  • Một bộ phận lấy nét: điều khiển vị trí của các lớp thấu kính làm cho hình rõ nét.
  • Một màn trập: để định thời gian mở ra cho ánh sáng rọi vào phim/cảm biến ảnh.
  • Một khẩu độ nằm trong ống kính, tuỳ chỉnh lượng sáng đi qua ống kính.
  • Một hộp tối để gắn phim hoặc cảm biến ảnh chỉ nhận tác động của ánh sáng đi qua ống kính vào.

1. Cơ chế lấy nét
Máy ảnh lấy nét tự động (AF – autofocus) sử dụng một bộ cảm biến, một hệ thông mô-tơ lấy nét tự động. Có hãng thiết kết hệ thống AF dựa vào một bộ cảm biến, có hãng sử dụng dải cảm biến. Máy ảnh DSLR đều dùng bộ cảm biến AF để lấy nét qua ảnh hội tụ từ ống kính kết hợp với dãy cảm biến khác lo việc đo sáng. Các cảm biến đo sáng hoạt động ưu tiên vùng đo sáng theo cùng khu vực lấy nét. Máy ảnh dùng nhiều cảm biến AF cho phép người dùng chủ động chọn điểm lấy nét, hoặc thuật toán xác định chủ đề di chuyển để tự động điều chỉnh lấy nét. Canon gọi là “AI Servo”, Nikon gọi là “AF Continuous”.

972344_152721568263265_1427902451_n copy.tinhte.vn.Bắt nét chủ thể chuyển động

AF Active – AF chủ động: Khi bấm nhẹ vào nút chụp, máy ảnh phát ra một tia hồng ngoại hoặc sóng siêu âm dò quét khung ảnh. Cảm biến AF nhận được tín hiệu phản xạ, máy ảnh sẽ điều khiển mô-tơ chuyển dịch các thấu kính trong ống kính, ông kính sẽ hội tụ vào vùng rõ nét của chủ đề. Bộ phận cảm biến càng nhạy thì việc lấy nét càng nhanh và đắt tiền. Cách này có thể lấy nét ở vùng tối, nhưng hiệu quả phụ thuộc vào khoảng cách tia hồng ngoại chiếu, và không xuyên qua gương.

AF passive – AF thụ động: không chủ động phát tia hồng ngoại để đo khoảng cách đến chủ đề, mà phân tích hình ảnh nhận được qua ống kính, vì vậy không đủ sáng thì việc lấy nét khó thực hiện được. Máy ảnh phải lấy nét theo 2 cơ chế:

  • Dò lệch pha (phase detection): hình ảnh rọi vào cảm biến AF (AF sensor) được phân ra làm đôi. Vị trí tương quan giữa hai hình ảnh này sẽ thay đổi theo vị trí của các thấu kính trong ống kính. Nếu hai hình ảnh này nằm lệch nhau, cảm biến AF sẽ tính toán vị trí cần thiết để ống kính đưa hai hình ảnh này về đúng vị trí chồng khít lên nhau. Mô-tơ trong ống kính hoạt động thực hiện việc thay đổi vị trí các thấu kính theo tín hiệu nhận được từ cảm biến AF. Theo cách này thì máy ảnh lấy nét tự động không phụ thuộc khoảng cách nào, vẫn có thể bám theo chủ đề di chuyển liên tục để lấy nét, với điều kiện đủ sáng cho việc lấy nét.
  • Đo tương phản (contrast measurement) là không đo khoảng cách nét mà đo lường độ tương phản ánh sáng mà bộ cảm biến nhận được từ ống kính, độ tương phản giữa các điểm trên cảm biến AF rõ nhất khi hình ảnh được lấy nét đúng. Kiểu này về lý thuyết là chậm hơn lấy nét dò lệch pha, không theo chủ thể chuyển động, nhưng độ chính xác cao hơn một khi lấy được nét.

q.

2. Khẩu độ ống kính

Khẩu độ là một lỗ hổng trong ống kính được tạo ra bởi các lá thép chồng chéo lên nhau. Các lá thép dịch chuyển tạo thành độ mở cho khẩu độ lớn hoặc nhỏ. Khẩu độ lớn thì ánh sáng đi qua nhiều, và ngươcj lại khép nhỏ khẩu độ thì ánh sáng đi qua ít. Có một vòng chỉnh trên máy ảnh điều khiển việc đóng mở này, gọi là vòng chỉnh khẩu độ (aperture control).

  • Độ mở của khẩu độ được gọi là f/số biểu thị tỷ lệ độ dài tiêu cự ống kính với đường kính của khẩu độ mở ra: f/số = tiêu cự / đường kính khẩu độ. Ví dụ: ống kính có tiêu cự 50mm, đường kính khẩu độ lớn nhất là 35mm, ta có số f/35 = 1.4 (làm tròn số). Khẩu độ thông thường trên ống kính có các nấc sau: 1.0 – 1.4 – 2 – 2.8 – 4 – 5.6 – 8 – 11 – 16 – 22 – 32
  • Số càng nhỏ thì độ mở của khẩu độ càng lớn. Mỗi nấc thường được gọi là 1 khẩu. Xoay vòng từ 5.6 -> 8 gọi là khép 1 khẩu và lượng sáng giảm 1/2, xoay từ 5.6 -> 4 gọi là mở 1 khẩu và lượng sáng tăng gấp đôi.

Nhiều dòng ống kính mới không có vòng chỉnh khẩu độ, độ mở khẩu độ lớn hay nhỏ được điều khiển bằng bánh xe điện tử trên thân máy và chỉ số xuất hiện trên kính ngắm hoặc LCD. Một ống kính ghi Nikon 35mm f/1.4 tức là hãng Nikon sản xuất, tiêu cự 35mm, khẩu độ mở lớn nhất của ống kính này là f/1.4.
-6.

3. Khẩu độ và độ nét – Vùng ảnh rõ nét
Khoảng cách mà chủ đề hoặc sự vật hiện rõ nét trong khung ảnh được gọi là vùng ảnh rõ, độ sâu trường ảnh hoặc gọi là chiều sâu ảnh trường (depth of field). Chính khẩu độ ảnh hưởng đến chiều sâu ảnh trường này. Khảu độ khép càng nhỏ thì vùng ảnh rõ càng sâu; khẩu độ mở càng lớn thì vùng ảnh rõ càng cạn.

Khi ngắm qua ống ngắm, ống kính luôn mở lớn hết cỡ để giúp ta lấy nét, ống kính chỉ đóng các lá khẩu theo khẩu độ được chỉnh khi ta bấm nút chụp để màn trập mở ra. Vì vậy, những gì ta thấy qua ống ngắm không đúng như vùng ảnh rõ sau khi chụp, nên để nhìn thấy hiệu quả của vùng ảnh rõ ngay lúc ngắm, ta bấm vào nút xem trước “depth of field preview”. Nút này tạm thời điều khiển khép khẩu độ nhỏ lại theo số khẩu độ người chụp chỉnh, khung ảnh sẽ tối hơn nhưng chiều sâu của ảnh hiện rõ hơn.
10314692_237790093089745_5759123234188074861_n copy.tinhte.vn.

Nikon D200 – 1/30s – f/16

4. Màn trập và tốc độ màn trập
Màn trập (shutter) là bộ phận người chụp dùng để quyết định thời lượng mà ánh sáng tiếp xúc với bề mặt phim hoặc cảm biến ảnh. Thời đầu máy ảnh không có màn trập. Người chụp mở nắp ống kính và đóng lại bằng tay sau một quảng thời gian mà họ nghĩ là đủ sáng rồi. Về sau, những tấm phim có độ nhạy sáng cao, thời gian lộ sáng rất nhanh nên người ta chế ra cái màn trập. Màn trập có 2 loại:

  • Màn trập nằm trong thân máy (focal plane shutter) gồm hai màn đen bằng nhiều lá thép kết hợp xếp chồng khít lên nhau để cản sáng. Khi bấm nút trập, tấm thứ nhất dịch chuyển sang một bên để lộ mặt bộ cảm biến ra ánh sáng, sau khoảng thời gian ấn định thì tấm thứ hai dịch chuyển theo tấm thứ nhất che kín mặt bộ cảm biến lại, kết thúc việc lộ sáng. Ở tốc độ nhanh thì tấm màn thứ hai sẽ theo sát tấm thứ nhất tạo thành một khe hở hẹp, chỉ cho lộ sáng từng phần mặt bộ cảm biến trong quá trình vận hành của màn trập. Loại này hạn chế về tốc độ khi dùng với flash, vì mỗi thời điểm, màn trập chỉ cho lộ sáng một phần mặt bộ cảm biến, nên flash chỉ có thể đồng bộ với mặt cảm biến ở tốc độ chậm.
  • Màn trập nằm trong ống kính (leaf shutter) thường kiêm luôn vai trò khẩu độ. Khi nhấn nút trập (shutter release), vòng các lá thép mở ra theo kích thước khẩu độ để ánh sáng đi vào bộ cảm biến, sau đó đóng lại sau thời gian đã được ấn định, kết thúc việc lộ sáng. Màn trập kiểu này rất êm và có thể đồng bộ với đèn flash ở mọi tốc độ.

000003a.tinhte.vn.
5. Điều chỉnh tốc độ màn trập
Tốc độ của màn trập xác định khoảng thời gian ánh sáng sẽ tác động vào bộ cảm biến và được điều chỉnh bằng một vòng chỉnh tốc độ trên thân máy (shutter dial). Các chỉ số chỉ tốc độ màn trập là con số tỷ lệ so với 1 giây, như 500 nghĩa là 1/500 giây. Các chỉ số thông thường chỉ tốc độ màn trập: 30s – 15s – 8s – 4s – 2s – 1s – 2 – 4 – 8 – 15 – 30 – 6- – 125 – 250 – 500 – 1000 – 2000 – 4000 – 8000 …
Mỗi nấc tốc độ tương ứng thời gian màn trập mở nhanh gấp đôi nấc đứng trước nó và bằng 1/2 nấc đứng sau nó. 1/125 nhanh gấp đôi tốc độ 1/60 và 1/250 nhanh gấp đôi 1/125 chẳng hạn.
-4.tinhte.vn.

Nikon D3 ISO100 – 30s – f/16

Màn trập còn có thể thiết đặt tốc độ B (Bulb) hay T (Time). Khi chọn tốc độ này, chừng nào nút bấm chụp còn nhấn xuống thì màn trập còn mở ra cho cảm biến lộ sáng.

* Tốc độ an toàn tối thiểu:

Khi chụp ở tốc độ chậm, sự rung lắc của tay cầm tác động lên thân máy làm mờ nhoè hình ảnh, nên công nghệ chống rung IS (image stabiliser) của Canon, VR (vibration reduction) của Nikon …khi tích hợp vào các ống kính hay thân máy giúp giảm mờ nhoè ảnh. Người ta có thể chụp ảnh rõ nét ở một khoảng tốc độ chậm nào đó, nhưng không phải ống kính nào cũng có tính năng chống rung.

2381338_thubanbotui_tocdomantrap_B.tinhte.vn.

Để hạn chế sự rung lắc máy ảnh khi chụp ở tốc độ quá chậm, chúng ta có cái bảng gợi ý trên. Trước đây, theo kinh nghiệm của nhiều người chụp ảnh đúc kết lại thành nguyên tắc, tuy không hoàn toàn chính xác 100%, nhưng có hiệu quả trong thực tế đa phần cho những người bắt đầu như anh em chúng ta, đó là thiết đặt tốc độ màn trập (chúng ta hay dùng từ “tốc độ chụp” là chưa chính xác) đối ứng với tiêu cự của ống kính (tiêu cự tương ứng với máy ảnh khổ film 35mm) đang sử dụng trên máy ảnh. Ví dụ, nếu ta đang sử dụng ống kính một tiêu cự 60mm trên máy ảnh fullframe, thì tốc độ màn trập tối thiểu nên chọn là 1/60 giây; nếu cùng ống kính tiêu cự 60mm gắn trên thân máy ảnh có cảm quang APS-C, tức là hệ số crop 1.5x tức tiêu cự tương ứng với ống kính trên lúc đó là 90mm, thì tốc độ màn trập nên chọn là 1/90 giây. Để đơn giản và khỏi phải tính toán thì bạn cứ nhân đôi tiêu cự lên, chẳng hạn với ống kính tiêu cự 60mm, tốc độ màn trập được chọn để ảnh không bị mờ nhoè là 1/120s hoặc nhanh hơn. Xin nhắc lại nguyên tắc này là đúc kết từ kinh nghiệm thực tế của nhiều người, không phải là nguyên lý của nhiếp ảnh.

Có nhiều trường hợp, cố tạo sự mờ nhoè để bức ảnh sinh động hơn, có hồn hơn, và đạt được ý đồ của người chụp hơn, thì người chụp sẽ chọn tốc độ chậm có chủ ý.

-1.tinhte.vn.
Tạo cảm giác rock khi cố ý chụp mờ tay trống

6. Phối hợp tốc độ và khẩu độ
Tốc độ và khẩu độ sẽ được phối hợp với nhau để điều chỉnh lượng sáng tác dụng vào bộ cảm biến. Để dễ hình dung, ta ví dụ cái ly hứng nước ở cái vòi. Vòi mở lớn, ly nhanh đầy. Vặn vòi nhỏ cho rỉ từng giọt, cái ly đầy nước sau một khoảng thời gian dài. Tốc độ và khẩu độ làm việc với nhau gần như vậy.
knowledge5_1_1.

Với lượng sáng lớn (khẩu lớn) thì cảm biến chỉ cần khoảng thời gian lộ sáng ngắn (tốc độ nhanh) là nhận đủ lượng sáng cần thiết (đủ sáng). Với cùng một cường độ sáng, cặp thông số 1/500 – f/4, 1/125 – f/5.6, 1/60 – f/8 hay 1/30 – f/11 … có cùng lượng sáng vào bộ cảm biến như nhau.

Như vậy, với cùng một cường độ sáng, ta có thể dùng nhiều cặp tốc độ khẩu độ khác nhau để cho cùng một lượng sáng như nhau đi vào cảm biến ảnh. Nói cách khác, với một giá trị lộ sáng (exposure value – EV), ta có nhiều tuỳ chọn thời chụp (tốc độ phối hợp với khẩu độ) khác nhau tuỳ ý đồ riêng. Chẳng hạn muốn lấy vùng ảnh rõ (dof) thật sâu thì dùng tốc độ chậm – khẩu độ nhỏ, muốn bắt dính chuyển động thì dùng tốc độ nhanh – khẩu độ lớn.

183100_119356164933139_424251736_n.tinhte.vn.
Bắt dính chuyển động của thiếu nữ

7. Thiết lập tốc độ màn trập thế nào?
Trong nhiều tuỳ chọn phương thức chụp của máy ảnh, có phương thức thiết đặt tốc độ tự động. Trên các dòng máy DSLRvà nhiều loại máy ảnh khác, có một nút gọi là ưu tiên tốc độ. Thường được đánh dấu bằng chữ “S” (Nikon) hoặc “Tv” (Canon). Bằng cách chuyển qua chế độ ưu tiên tốc độ này, người chụp chủ động kiểm soát tốc độ và để cho máy tuỳ ứng trị số khẩu độ thích hợp cho chính xác với môi trường ánh sáng. Các chỉ số tốc độ thường giới hạn từ 30 giây đến 1/8000 giây trên một số dòng máy mình biết. Ngoài ra, có máy ảnh cho phép chụp với chế độ “Bulb”, cho phép giữ nguyên vị trí màn trập mở khi bấm nút chụp và chỉ đóng khi nút bấm chụp được thả ra. Tốc độ màn trập khi đó dựa vào việc người chụp giữ nút chụp lâu hay mau. Ở chế độ “Bulb” này, sự rung lắc là không tránh khỏi, nên phải gắn máy ảnh lên chân máy hoặc đặt máy ảnh cố định trên bề mặt nào đó, thậm chí phải sử dụng một phụ kiện bấm máy bên ngoài, hay gọi là remote, dây bấm mềm…
-3.

Máy ảnh như công cụ của một nghệ nhân. Làm chủ máy càng chắc, cầm máy càng vững, thành thạo với các chức năng điều khiển máy ảnh, thì khả năng bắt được nhiều khoảnh khắc và ít sai phạm đáng tiếc hơn.

Bài viết liên quan có thể cần với bạn:

  1. Làm chủ máy ảnh của bạn – Phần 1
  2. Tốc độ màn trập và tại sao ảnh không nét?
  3. Khẩu độ – Lượng sáng qua ống kính.
  4. Thủ bản bỏ túi: Tốc độ màn trập.

919903_123242521211170_1262041449_o.tinhte.vn.