Today I Learned

TIL, 2018-03-12, History Lesson

Musings

  • Reviewing through “Growing Rails Applications in Practice.” I still completely agree on controllers and models. AR models should really be as slim as possible.
  • Checked out some use cases for NoSQL. I think it’s for bigger applications. At the start, you stick with pure RDBMSes.
  • Elixir’s defmacro __using__.

  • When to index?
    • You can add a double index when you need to do something like SELECT name from repositories where owner_id > 500. Create an index over owner_id and name.
    • Common rules of indexing, querying, and data modeling.
      • Any columns involved in queries should be indexed, unless there is already a covering index.
        • Problems with redundant index: it takes up precious space, and adding an index slows down updates/inserts/deletes because those operations also have to edit the index.
      • Index prefix vs index.
        • If you’re indexing over a long data type, you can use this.
        • If it’s things like “query usernames starting with ‘a’”.
        • How long? Long enough to differentiate values within the field, and base it off of real data if possible.
      • Use an OR (UNION) to satisfy.
        • EXPLAIN shows what indexes were use and how many rows were scanned.
        • The OR operator is limited because MySQL can only use one index per table during a query, so it chooses to use neither.
        • You can use a UNION if there’s no index that covers both conditionals at the same time.
      • If there’s an index, you’re all set.
        • You can use a FORCE INDEX or USE INDEX or IGNORE INDEX if MySQL is not choosing a performant index.
      • Avoid redundant data across tables.
        • Unless additional reads/JOINS are causing a large amount of performance overhead.
        • Unless if there is a high ratio of reads to writes.
        • Cost: Database changes (migrations) and data quality (since no longer normalized).
  • I just cleaned through Yehuda Katz talk about “The Next 5 Years of Rails” in 2012, that was freaky! It really happened.
  • Mistakes with the Repository Pattern
    • One repository per domain: separate per domain class: OrderRepository, ShippingRepository, ProductRepository.
    • Returning view models: Your repositories should return domain objects and the client of your repository can decide if it needs to do the mapping.
    • Saving/updating method in repositories: Do not have a save() or update() method. Think of a repository as a collection of domain objects in memory. Collections do not have a save or update() method. The pattern that comes with this is the Unit of Work pattern. After doing the operation, save it with another class.
    • repositories that return IQueryable. You should return domain objects.
    • The more complex your application grows, the more you may want to consider separating the read and write models, and then eventually, you’ll find in CQRS.
  • Q&A with Piotr Solnica.
    • Dry: Using both OO and FP features. Things to avoid in the Ruby ecosystem: monkey-patching, relying on object mutability. Promote: DI, object composition, type safety.
    • DI is easier in Ruby than in a statically-typed language like Scala.
    • Some people just have a certain preference for the DSL they use. ActiveModel vs dry-validation. Control flow in monads?
    • Making Ruby code more functional has made it simpler and faster. Crucial parts of your system, like data validation/type conversions/error handling.
    • Composition: when you use callable objects that don’t rely on state mutations, it’s much easier to compose them. You can change your approach to OO/FP. Two key factors that help me improve the design were moving away from relying on mutable state, and isolating the complexity of object construction via inversion of control containers.
    • Downside of dry-rb: they are small, simple abstractions, and people who are used to more complex, well-integrated frameworks will simply have a steeper learning curve.
    • No need to change objects, and you can visualize an application as a series of data transformations rather than object interactions, where data is part of state in order to “encapsulate” it.
    • Instead of: creating an AR instance then saving, you can validate the params, then ask a Repository object to persist valid data.
    • dry-struct, then dry-validation.
  • Glanced through some TDD things.
    • Hexagonal Rails and The Ludicrous Terminal Application.
      • Very rare to do “swappable data stores and UIs” (though in Daryllxd that’s what’s happening right now, lol).
      • More likely, you need to separate domain from persistence since they change for different reasons.
      • Whenever Rails updates, if you put int business logic in controllers and Ar models, you run the risk of having to change the objects containing the application’s business logic.
      • When you have to change business logic in order to speed of persisting and retrieving data from the data store. When you need to change persistence strategies to accommodate tables, stored procedures, sharding, if you combined business/persistence logic, your business logic will have to change with it.
      • When business logic gets entangled with the framework, velocity slows, defect rates increase, and developer happiness drops.
      • Other consumers of the app: Scheduled tasks, jobs, JSON API.
    • Hexagonal Architecture for Rails Developers
      • Modules can be developed and deployed independently.
      • The application becomes easy to test because the logic that needs to be tested depends neither on the UI of the application nor the database.
      • Techniques
        • Case services: A component taht is responsible for the coordination logic we tend to put into our controllers.
        • Passive controller: No decisions whether the use case it invoke succeeded or failed. It just returns whatever to the outside world.
        • Adapters: OrderController and OrderRepository.
        • The application knows nothing about persistence. It uses repositories to talk to the database.

Full Stack React

  • If you do this (from Babel’s transform-class-properties plugin), the this inside the function is bound to the component, as expected.
handleUp = () => (
  this.props.onVote(this.props.id, "pants")
);
  • I can do console.log(this.state).
  • Property initializers: We can use arrow functions for custom component methods (and avoid having to bind this).
  • We can define the initial state outside of the constructor().

This project is maintained by daryllxd