Topic 32-34

tags: The Pragmatic Programmer

Topic 32 Configuration

  • Code relies on values that may change after the application has gone live, keep those values external to the app.
  • Application will run in different environments, and potentially for different customers
  • Keep the environment- and customer-specific values outside the app
  • Parameterize your application: the code adapts to the places it runs.

Tip 55: Parameterize Your App Using External Configuration

Look for anything that you know will have to change that you can express outside your main body of code

Common things put in configuration data
  • Credentials for external services (database, third party APIs, and so on)
  • Logging levels and destinations
  • Port, IP address, machine, and cluster names the app uses
  • Environment-specific validation parameters
  • Externally set parameters, such as tax rates
  • Site-specific formatting details
  • License keys

Static Configuration

Flat files or database tables

Format:

  • Popular flat files type: YAML, JSON (example from FR Studio)
  • Better to store in database when:
    • Information is structured
    • Likely to be changed by the customer (ex: sales tax rates)

The configuration:

  • Is read into your application as a data structure
  • Normally when the application starts
  • Commonly is made global, easier for any code to get to the values.

The author suggest us NOT to do the above.
Instead, wrap the configuration information behind a (thin) API.
This decouples our code from the details of the representation of configuration.

Configuration-As-A-Service

Rather than flat file or database, the authors suggest configuration to be stored behind a service API. (example from FR Studio)

Benifits:

  • Multiple applications can share configuration information, with authentication and access control limiting what each can see
  • Configuration changes can be made globally
  • The configuration data can be maintained via a specialized UI
  • The configuration data becomes dynamic !!!

:no_entry: Static Configuation

  • We have to stop and restart an application to change a single parameter.

:heavy_check_mark: Configuration service

  • Components of the application could register for notifications of updates to parameters they use.
  • Service could send them messages containing new values when they are changed.
  • No need to rebuild, when configuration values change.

Reminders:

  • Don’t Write Dodo-Code:
    Without external configuration, your code is not as adaptable or flexible as it could be.
  • Don’t Overdo It:
    Don’t push decisions to configuration out of laziness.

Chapter 6 Concurrency: Introduction

  • Definition
    • Concurrency

      • When the execution of two or more pieces of code act as if they run at the same time.
      • To have concurrency, you need to run code in an environment that can switch execution between different parts of your code when it is running.
        => JavaScript Event Loop

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

    • Parallelism

      • When they do run at the same time.
      • To have parallelism, you need hardware that can do two things at once. (ex: multiple cores in a CPU, multiple CPUs in a computer, or multiple computers connected together)

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

Everything Is Concurrent

Concurrency is a requirement if you want your application to be able to deal with the real world, where things are asynchronous: users are interacting, data is being fetched, external services are being called, all at the same time.

Topic 33: Breaking Temporal Coupling

Two aspects of time that are important to us:

  • Concurrency: things happening at the sametime
  • Ordering: the relative positions of things in time

Temporal coupling: coupling in time, ex:

  • Method A must always be called before method B
  • Only one report can be run at a time
  • Must wait for the screen to redraw before the button click is received.

:arrow_right: We need to allow for concurrency and to think about decoupling any time or order dependencies.

Looking for Concurrency

Find out:

  • What can happen at the same time
  • What must happen in a strict order

:star: Activity Diagram: one way to capture the workflow

Maximize parallelism by identifying activities that could be performed in parallel, but aren’t.

Tip 56: Analyze Workflow to Improve Concurrency

Example: steps of robotic piña colada maker

  1. Open blender
  2. Open piña colada mix
  3. Put mix in blender
  4. Measure 1/2 cup white rum
  5. Pour in rum
  6. Add 2 cups of ice
  7. Close blender
  8. Liquefy for 1 minute
  9. Open blender
  10. Get glasses
  11. Get pink umbrellas
  12. Serve

:arrow_down: Applying activity diagram

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

What is found:

  • The top-level tasks (1, 2, 4, 10, and 11) can all happen concurrently, up front.
  • Tasks 3, 5, and 6 can happen in parallel later.

Opportunities for Concurrency

Activity diagrams show the potential areas of concurrency, but have nothing to say about whether these areas are worth exploiting. :arrow_right: This is where the design part comes in

Robotic piña colada maker example:
Number 8, liquify, will take a minute. During that time, our bartender can get the glasses and umbrellas (activities 10 and 11) and probably still have time to serve another customer.

Find activities that take time, but not time in our code. ex:

  • Querying a database
  • accessing an external service
  • waiting for user input

These are opportunities to do something more productive.

Opportunities for Parallelism

Parallelism is a hardware concern

  • Split into pieces of work that are relatively independent—where each can proceed without waiting for anything from the others.
  • Split it into independent chunks, process each in parallel, then combine the results.

:heavy_exclamation_mark: Identifying Opportunities Is the Easy Part. The tricky part: how can we implement it safely.

Challenges
How many tasks do you perform in parallel when you get ready for work in the morning? Could you express this in a UML activity diagram? Can you find some way to get ready more quickly by increasing concurrency?

Topic 34: Shared State Is Incorrect State

The apple pie example

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • The problem is the shared state. Each server in the restaurant looked into the display case without regard for the other.
  • The problem here is not that two processes can write to the same memory. The problem is that neither process can guarantee that its view of that memory is consistent.

If the value in the display case changes, their memory (which they are using to make decisions) is now out of date.

This is all because the fetching and then updating the pie count is not an atomic operation: the underlying value can change in the middle.

Semaphores and Other Forms of Mutual Exclusion

Semaphore: a thing that only one person can own at a time

Apple pie example with Semaphore

case_semaphore.lock()

if display_case.pie_count > 0
    promise_pie_to_customer()
    display_case.take_pie()
    give_pie_to_customer()
end

case_semaphore.unlock()

Problems with this approach:

  • This is a convention that everyone need to agree and remember, or chaos.
  • Delegates responsibility for protecting access to the pie case to the people who use it.

Make the Resource Transactional

centralize the control of Semaphore

Misconception example:

slice = display_case.get_pie_if_available()
    if slice
    give_pie_to_customer()
end

def get_pie_if_available()         ####
    if @slices.size > 0            #
        update_sales_data(:pie)    #
        return @slices.shift       #
    else                           # incorrect code!
        false                      #
    end                            #
end                                ####

Correct way:

def get_pie_if_available()
    @case_semaphore.lock()
    
    try {
        if @slices.size > 0
            update_sales_data(:pie)
            return @slices.shift
        else
            false
        end
    }
    ensure {
        @case_semaphore.unlock()
    }
end

Multiple Resource Transactions

Apple pie with ice cream as a single order

slice = display_case.get_pie_if_available()
if slice
    try {
        scoop = freezer.get_ice_cream_if_available()
        if scoop
        try {
            give_order_to_customer()
        }
        rescue {
            freezer.give_back(scoop)
        }
        end
    }
    rescue {
        display_case.give_back(slice)
    }
end

Problems with this approach:

  • The code is now really ugly
  • What about more resource?

The pragmatic approach would be to say that “apple pie à la mode” is its own resource. We’d move this code into a new module, and then the client could just say “get me apple pie with ice cream” and it either succeeds or fails.

  • Composite dishes
  • Generic get_menu_item

To be completed