fujitamasashi255 / mysql_performance_logger

MIT License
0 stars 0 forks source link

mysql #6

Open fujitamasashi255 opened 8 months ago

fujitamasashi255 commented 8 months ago

パフォーマンススキーマテーブル

https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-table-descriptions.html

以下、第4回 MySQLチューニング(3) パフォーマンススキーマ より引用

計器(インストゥルメント)とは

パフォーマンススキーマは性能統計情報を記録するストレージエンジンの一種として実装されており、performance_schemaスキーマのテーブルに格納された処理のレイテンシ(ピコ秒単位)やデータのバイト数、ソースでの位置、オブジェクトのデータなどに対してSQLでアクセス可能です。MySQLサーバのソースコード中にある “⁠instrumentation point⁠”(または “⁠instrument⁠” と表現される)にて「イベント」毎の処理時間や処理データ量などを計測および表示します。

パフォーマンススキーマの階層構造

パフォーマンススキーマのテーブル名や格納されている値の“⁠Instruments⁠”名は階層構造の各レベルに対応しています。

パフォーマンススキーマのデータ格納テーブルの名称

テーブル名の末尾が

SYSスキーマ

パフォーマンススキーマは非常に細かな粒度で情報が取得できるものの、データベース管理者やアプリケーション開発者にとっては細かすぎる場合もあります。そこでMySQLではパフォーマンススキーマやインフォメーションスキーマのデータに対して、よりシンプルなビューの集合であるSYSスキーマを用意し、性能問題の検出や診断などのタスクをより支援できるように改善しています。

fujitamasashi255 commented 8 months ago

パフォーマンススキーマロックテーブル

performance_schema.data_locks

https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-data-locks-table.html

カラム一覧 ``` show create table performance_schema.data_locks; ENGINE ENGINE_LOCK_ID ENGINE_TRANSACTION_ID THREAD_ID EVENT_ID OBJECT_SCHEMA OBJECT_NAME PARTITION_NAME SUBPARTITION_NAME INDEX_NAME OBJECT_INSTANCE_BEGIN LOCK_TYPE LOCK_MODE LOCK_STATUS LOCK_DATADEFAULT NULL, PRIMARY KEY (`ENGINE_LOCK_ID`,`ENGINE`), KEY `ENGINE_TRANSACTION_ID` (`ENGINE_TRANSACTION_ID`,`ENGINE`), KEY `THREAD_ID` (`THREAD_ID`,`EVENT_ID`), KEY `OBJECT_SCHEMA` (`OBJECT_SCHEMA`,`OBJECT_NAME`,`PARTITION_NAME`,`SUBPARTITION_NAME`) ```

performance_schema.data_lock_waits

https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-data-lock-waits-table.html

カラム一覧 ``` show create table performance_schema.data_lock_waits; ENGINE REQUESTING_ENGINE_LOCK_ID REQUESTING_ENGINE_TRANSACTION_ID REQUESTING_THREAD_ID REQUESTING_EVENT_ID REQUESTING_OBJECT_INSTANCE_BEGIN BLOCKING_ENGINE_LOCK_ID BLOCKING_ENGINE_TRANSACTION_ID BLOCKING_THREAD_ID BLOCKING_EVENT_ID BLOCKING_OBJECT_INSTANCE_BEGIN KEY `REQUESTING_ENGINE_LOCK_ID` (`REQUESTING_ENGINE_LOCK_ID`,`ENGINE`), KEY `BLOCKING_ENGINE_LOCK_ID` (`BLOCKING_ENGINE_LOCK_ID`,`ENGINE`), KEY `REQUESTING_ENGINE_TRANSACTION_ID` (`REQUESTING_ENGINE_TRANSACTION_ID`,`ENGINE`), KEY `BLOCKING_ENGINE_TRANSACTION_ID` (`BLOCKING_ENGINE_TRANSACTION_ID`,`ENGINE`), KEY `REQUESTING_THREAD_ID` (`REQUESTING_THREAD_ID`,`REQUESTING_EVENT_ID`), KEY `BLOCKING_THREAD_ID` (`BLOCKING_THREAD_ID`,`BLOCKING_EVENT_ID`) ```
fujitamasashi255 commented 8 months ago

パフォーマンススキーマステートメントイベントテーブル

https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-statement-tables.html

カラム一覧 カラム一覧の意味:https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-events-statements-current-table.html ``` show create table performance_schema.events_statements_history; THREAD_ID EVENT_ID END_EVENT_ID EVENT_NAME SOURCE TIMER_START TIMER_END TIMER_WAIT LOCK_TIME SQL_TEXT DIGEST DIGEST_TEXT CURRENT_SCHEMA OBJECT_TYPE OBJECT_SCHEMA OBJECT_NAME OBJECT_INSTANCE_BEGIN MYSQL_ERRNO RETURNED_SQLSTATE MESSAGE_TEXT ERRORS WARNINGS ROWS_AFFECTED ROWS_SENT ROWS_EXAMINED CREATED_TMP_DISK_TABLES CREATED_TMP_TABLES SELECT_FULL_JOIN SELECT_FULL_RANGE_JOIN SELECT_RANGE SELECT_RANGE_CHECK SELECT_SCAN SORT_MERGE_PASSES SORT_RANGE SORT_ROWS SORT_SCAN NO_INDEX_USED NO_GOOD_INDEX_USED NESTING_EVENT_ID NESTING_EVENT_TYPENULL, NESTING_EVENT_LEVEL STATEMENT_ID CPU_TIME MAX_CONTROLLED_MEMORY MAX_TOTAL_MEMORY EXECUTION_ENGINE PRIMARY KEY (`THREAD_ID`,`EVENT_ID`) ```
fujitamasashi255 commented 8 months ago

パフォーマンススキーマのトランザクションテーブル

https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-transaction-tables.html

カラム一覧 ``` show create table performance_schema.events_transactions_history; THREAD_ID EVENT_ID END_EVENT_ID EVENT_NAME STATE TRX_ID GTID XID_FORMAT_ID XID_GTRID XID_BQUAL XA_STATE SOURCE TIMER_START TIMER_END TIMER_WAIT ACCESS_MODE ISOLATION_LEVEL AUTOCOMMIT NUMBER_OF_SAVEPOINTS NUMBER_OF_ROLLBACK_TO_SAVEPOINT NUMBER_OF_RELEASE_SAVEPOINT OBJECT_INSTANCE_BEGIN NESTING_EVENT_ID NESTING_EVENT_TYPENULL, PRIMARY KEY (`THREAD_ID`,`EVENT_ID`) ```
fujitamasashi255 commented 8 months ago

叩き台1

class MySqlPerformanceLogger
  QUERY = <<-SQL
    SELECT * FROM sys.innodb_lock_waits
  SQL

  # 以下のようなものもあり
  # select
  #     locks.OBJECT_NAME,
  #     locks.INDEX_NAME,
  #     locks.LOCK_TYPE,
  #     locks.LOCK_MODE,
  #     locks.LOCK_STATUS,
  #     locks.LOCK_DATA,
  #     events.LOCK_TIME,
  #     events.SQL_TEXT
  # from
  #     performance_schema.data_locks locks
  #     join
  #         performance_schema.events_statements_history events
  #     on  locks.event_id = events.event_id
  #     and locks.thread_id = events.thread_id
  # ;

  def initialize
    logger = Logger.new($stdout)
  end

  def self.measure(&block)
    t1 = Thread.new do
      yield block
    end

    t2 = Thread.new do
      5.times do |n|
        puts <<-EOS
          ーーーーーーーーーーーーーーー #{ n + 1 }回目 ーーーーーーーーーーーーーーーーーーーー
        EOS
        res = ActiveRecord::Base.connection.select_all(QUERY)
        puts res.rows[0]
        sleep 0.01
      end
    end

    t1.join
    t2.join
  end
end

MySqlPerformanceLogger.measure do
  ActiveRecord::Base.transaction do
    puts "ユーザーをロック"
    user = User.lock.find(1)

    puts "ユーザーをupdate"
    user.update(name: "masa")

    puts "ロールバック"
    raise ActiveRecord::Rollback
  end
end

結果

ーーーーーーーーーーーーーーー 1回目 ーーーーーーーーーーーーーーーーーーーー
ユーザーをロック
ーーーーーーーーーーーーーーー 2回目 ーーーーーーーーーーーーーーーーーーーー

ユーザーをupdate
ロールバック
ーーーーーーーーーーーーーーー 3回目 ーーーーーーーーーーーーーーーーーーーー

ーーーーーーーーーーーーーーー 4回目 ーーーーーーーーーーーーーーーーーーーー

ーーーーーーーーーーーーーーー 5回目 ーーーーーーーーーーーーーーーーーーーー
fujitamasashi255 commented 8 months ago

叩き台2

ActiveRecord::Base.transaction do puts "ユーザーをロック" user = User.lock.find(1)

puts "ユーザーをupdate" user.update(name: "masa")

puts "ロールバック" raise ActiveRecord::Rollback end

fujitamasashi255 commented 8 months ago

https://blog.agile.esm.co.jp/entry/columns-by-as-phrase-have-no-db-type

https://madogiwa0124.hatenablog.com/entry/2020/03/29/151836

fujitamasashi255 commented 8 months ago

Docker rm volume $(docker volume ls -q) https://qiita.com/Ikumi/items/b319a12d7e2c9f7b904d

Docker system df https://zenn.dev/bon/articles/docker-nospace-error

docker system prune help docker system prune --volumes https://docs.docker.jp/config/pruning.html

Error response from daemon: cannot stop container: d76d6e2a5f8aed35a4462b11c591c210fe18dc11e38063305cbf636de85fa91e: tried to kill container, but did not receive an exit event https://qiita.com/hanlio/items/6bcb3667147f2d5633de

fujitamasashi255 commented 8 months ago

https://dev.to/ably/alternatives-to-websockets-for-realtime-features-4mkp

https://learn.microsoft.com/en-us/archive/blogs/nakama/453

fujitamasashi255 commented 8 months ago

https://github.blog/jp/2021-01-06-commits-are-snapshots-not-diffs/

https://stackoverflow.com/questions/44052660/is-it-possible-to-use-ruby-refinements-to-change-the-behavior-of-a-controller-ac

https://learn.microsoft.com/ja-jp/dotnet/standard/exceptions/best-practices-for-exceptions?redirectedfrom=MSDN

https://www.amazon.co.jp/Exception-handling-Java-comprehensive-exceptions/dp/B09BYBJ4ZD

https://www.amazon.co.jp/Advanced-Exception-Handling-Techniques-Computer/dp/3540374434

[第9回]効果のないインデックス---「性別」に付けても効果なし https://xtech.nikkei.com/it/article/COLUMN/20070919/282317/

理屈で考える、データベースのチューニング https://techblog.raccoon.ne.jp/archives/1601618994.html

fujitamasashi255 commented 5 months ago

Rails

cleanj-rails.org https://discourse.clean-rails.org/

concern, concering

バリデータクラス

ActiveRecord の接続管理の仕組み

fujitamasashi255 commented 5 months ago

もう絶対迷わないエラーレスポンスの作り方【RFC7807】 https://qiita.com/akkino_D-En/items/a54bdf5dadc2daba1ab4

RailsにおけるRESTfulなURL設計勉強会 千駄ヶ谷.rb #12 に参加してきた https://joker1007.hatenablog.com/entry/20120723/1343064276

Railsの例外一覧出力 ```ruby StandardError.descendants.filter{ |klass| klass.name.start_with?("Active") }.sort_by{ |klass| klass.name } => [ # ーーーーーーーーActiveHashーーーーーーーー ActiveHash::Enum::DuplicateEnumAccessor, ActiveHash::FileTypeMismatchError, ActiveHash::IdError, ActiveHash::RecordNotFound, ActiveHash::ReservedFieldError, # ーーーーーーーーActiveJobーーーーーーーー ActiveJob::DeserializationError, ActiveJob::EnqueueError, ActiveJob::SerializationError, # ーーーーーーーーActiveModelーーーーーーーー ActiveModel::ForbiddenAttributesError, ActiveModel::MissingAttributeError, ActiveModel::RangeError, ActiveModel::Serializer::CollectionSerializer::CannotInferRootKeyError, ActiveModel::Serializer::UndefinedCacheKey, ActiveModel::StrictValidationFailed, ActiveModel::UnknownAttributeError, ActiveModel::ValidationError, # ーーーーーーーーActiveRecordーーーーーーーー ActiveRecord::ActiveJobRequiredError, ActiveRecord::ActiveRecordError, ActiveRecord::AdapterNotFound, ActiveRecord::AdapterNotSpecified, ActiveRecord::AdapterTimeout, ActiveRecord::AmbiguousSourceReflectionForThroughAssociation, ActiveRecord::AssociationNotFoundError, ActiveRecord::AssociationTypeMismatch, ActiveRecord::AsynchronousQueryInsideTransactionError, ActiveRecord::AttributeAssignmentError, ActiveRecord::AttributeMethods::Serialization::ColumnNotSerializableError, ActiveRecord::ConcurrentMigrationError, ActiveRecord::ConfigurationError, ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionTimeoutError, ActiveRecord::DangerousAttributeError, ActiveRecord::DatabaseAlreadyExists, ActiveRecord::DatabaseConfigurations::InvalidConfigurationError, ActiveRecord::DatabaseConnectionError, ActiveRecord::Deadlocked, ActiveRecord::DeleteRestrictionError, ActiveRecord::DestroyAssociationAsyncError, ActiveRecord::DuplicateMigrationNameError, ActiveRecord::DuplicateMigrationVersionError, ActiveRecord::EagerLoadPolymorphicError, ActiveRecord::Encryption::Errors::Base, ActiveRecord::Encryption::Errors::Configuration, ActiveRecord::Encryption::Errors::Decryption, ActiveRecord::Encryption::Errors::Encoding, ActiveRecord::Encryption::Errors::EncryptedContentIntegrity, ActiveRecord::Encryption::Errors::Encryption, ActiveRecord::Encryption::Errors::ForbiddenClass, ActiveRecord::EnvironmentMismatchError, ActiveRecord::EnvironmentStorageError, ActiveRecord::ExclusiveConnectionTimeoutError, ActiveRecord::HasManyThroughAssociationNotFoundError, ActiveRecord::HasManyThroughAssociationPointlessSourceTypeError, ActiveRecord::HasManyThroughAssociationPolymorphicSourceError, ActiveRecord::HasManyThroughAssociationPolymorphicThroughError, ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, ActiveRecord::HasManyThroughNestedAssociationsAreReadonly, ActiveRecord::HasManyThroughOrderError, ActiveRecord::HasManyThroughSourceAssociationNotFoundError, ActiveRecord::HasOneAssociationPolymorphicThroughError, ActiveRecord::HasOneThroughCantAssociateThroughCollection, ActiveRecord::HasOneThroughCantAssociateThroughHasOneOrManyReflection, ActiveRecord::HasOneThroughNestedAssociationsAreReadonly, ActiveRecord::IllegalMigrationNameError, ActiveRecord::ImmutableRelation, ActiveRecord::InvalidForeignKey, ActiveRecord::InverseOfAssociationNotFoundError, ActiveRecord::InverseOfAssociationRecursiveError, ActiveRecord::IrreversibleMigration, ActiveRecord::IrreversibleOrderError, ActiveRecord::LockWaitTimeout, ActiveRecord::MigrationError, ActiveRecord::MismatchedForeignKey, ActiveRecord::MultiparameterAssignmentErrors, ActiveRecord::NestedAttributes::TooManyRecords, ActiveRecord::NoDatabaseError, ActiveRecord::NoEnvironmentInSchemaError, ActiveRecord::NotNullViolation, ActiveRecord::PendingMigrationError, ActiveRecord::PreparedStatementCacheExpired, ActiveRecord::PreparedStatementInvalid, ActiveRecord::ProtectedEnvironmentError, ActiveRecord::QueryAborted, ActiveRecord::QueryCanceled, ActiveRecord::RangeError, ActiveRecord::ReadOnlyError, ActiveRecord::ReadOnlyRecord, ActiveRecord::RecordInvalid, ActiveRecord::RecordNotDestroyed, ActiveRecord::RecordNotFound, ActiveRecord::RecordNotSaved, ActiveRecord::RecordNotUnique, ActiveRecord::Rollback, ActiveRecord::SecureToken::MinimumLengthError, ActiveRecord::SerializationFailure, ActiveRecord::SerializationTypeMismatch, ActiveRecord::SoleRecordExceeded, ActiveRecord::StaleObjectError, ActiveRecord::StatementInvalid, ActiveRecord::StatementTimeout, ActiveRecord::StrictLoadingViolationError, ActiveRecord::SubclassNotFound, ActiveRecord::TableNotSpecified, ActiveRecord::Tasks::DatabaseNotSupported, ActiveRecord::ThroughCantAssociateThroughHasOneOrManyReflection, ActiveRecord::ThroughNestedAssociationsAreReadonly, ActiveRecord::TransactionIsolationError, ActiveRecord::TransactionRollbackError, ActiveRecord::TypeConflictError, ActiveRecord::UnknownAttributeReference, ActiveRecord::UnknownMigrationVersionError, ActiveRecord::UnknownPrimaryKey, ActiveRecord::ValueTooLong, ActiveRecord::WrappedDatabaseException, # ーーーーーーーーActiveStorageーーーーーーーー ActiveStorage::Error, ActiveStorage::FileNotFoundError, ActiveStorage::IntegrityError, ActiveStorage::InvariableError, ActiveStorage::PreviewError, ActiveStorage::UnpreviewableError, ActiveStorage::UnrepresentableError, # ーーーーーーーーActiveSupportーーーーーーーー ActiveSupport::ActionableError::NonActionable, ActiveSupport::Concern::MultipleIncludedBlocks, ActiveSupport::Concern::MultiplePrependBlocks, ActiveSupport::ConfigurationFile::FormatError, ActiveSupport::DeprecationException, ActiveSupport::EncryptedFile::InvalidKeyLengthError, ActiveSupport::EncryptedFile::MissingContentError, ActiveSupport::EncryptedFile::MissingKeyError, ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::Notifications::InstrumentationSubscriberError, ActiveSupport::SafeBuffer::SafeConcatError, ActiveSupport::XMLConverter::DisallowedType ] ```
fujitamasashi255 commented 5 months ago

コールバック

fujitamasashi255 commented 5 months ago

Terraform を使用するためのベスト プラクティス https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl=ja

システム運用アンチパターン ウェブオペレーション https://kakakakakku.hatenablog.com/entry/2023/10/30/090954

事前にデータ投入をした MySQL Docker イメージを作る場合は /docker-entrypoint-initdb.d を活用すると便利

ecsgo https://system.blog.uuum.jp/entry/2023/05/29/115452

ruby: 定数探索

datadog

ドキュメント:https://docs.datadoghq.com/ja/

ログ

https://docs.datadoghq.com/ja/logs/

メトリクス

https://docs.datadoghq.com/ja/metrics/

fujitamasashi255 commented 5 months ago

{repo_FQDN}/compare/branch1...branch2

https://qiita.com/fantasista_21jp/items/9419ca4ab3bb8e1ee4c5

fujitamasashi255 commented 5 months ago

frozen_string_literal: true

実行:rails runner log/runner/callback/code.rb

class MyClass extend ActiveModel::Callbacks define_model_callbacks :hello

callbackをはさまれるメソッド hello

ex: save, create

def hello _run_hello_callbacks do puts "へろー" end end

以下、コールバックを定義

before_hello :say

action before hello

def say puts "せい!" end end

MyClass.new.hello

ーーーーー

frozen_string_literal: true

実行:rails runner log/runner/callback/code2.rb

class MyCallback

action before hello

def before_hello(caller) puts "#{caller.class.name}" end end

class MyClass extend ActiveModel::Callbacks define_model_callbacks :hello

callbackをはさまれるメソッド hello

ex: save, create

def hello _run_hello_callbacks do puts "へろー" end end

以下、コールバックを定義

before_hello MyCallback.new end

MyClass.new.hello

fujitamasashi255 commented 5 months ago

abstract

extend ActiveModel::Callbacks

↓

include ActiveSupport::Callbacks
def define_model_callbacks(*callbacks)

# ===================================================

# define_model_callbacks(*callbacks) を実行
# (1)(2)が実行されて、メソッドが定義される

callbacks.each do |callback|
  define_callbacks(callback, options)                         #...(1)_run_callbacks などが定義される

  types.each do |type|
    send("_define_#{type}_model_callback", self, callback)    #...(2)before_hoge などが定義される(around, afterも)
  end
end

# ===================================================

# (1) define_callbacks(callback, options) を実行
# ここから ActiveSupport::Callback

def define_callbacks(*names)
  options = names.extract_options!

  names.each do |name|
    name = name.to_sym

    ([self] + self.descendants).each do |target|
      target.set_callbacks name, CallbackChain.new(name, options)
    end

    module_eval <<-RUBY, __FILE__, __LINE__ + 1
      def _run_#{name}_callbacks(&block)
        run_callbacks #{name.inspect}, &block
      end

      def self._#{name}_callbacks
        get_callbacks(#{name.inspect})
      end

      def self._#{name}_callbacks=(value)
        set_callbacks(#{name.inspect}, value)
      end

      def _#{name}_callbacks
        __callbacks[#{name.inspect}]
      end
    RUBY
  end
end

# ===================================================

# (2) send("_define_before_model_callback", self, callback) を実行
# before_hoge(*args, **options, &block) が定義される
# ActiveModel::Callback
klass.define_singleton_method("before_#{callback}") do |*args, **options, &block|
  options.assert_valid_keys(:if, :unless, :prepend)
  set_callback(:"#{callback}", :before, *args, options, &block)
end

# ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
# before_hoge(*args, **options, &block) を実行
set_callback(:"#{callback}", :before, *args, options, &block)

↓

# ここから ActiveSupport::Callback
def set_callback(name, *filter_list, &block)
  type, filters, options = normalize_callback_params(filter_list, block)

  self_chain = get_callbacks name
  mapped = filters.map do |filter|
    Callback.build(self_chain, filter, type, options)
  end

  __update_callbacks(name) do |target, chain|                           # ...(a)
    options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
    target.set_callbacks name, chain                                    # ...(b)
  end
end

↓

# (a) __update_callbacks
# This is used internally to append, prepend and skip callbacks to the CallbackChain.
def __update_callbacks(name) # :nodoc:
  self.descendants.prepend(self).reverse_each do |target|
    chain = target.get_callbacks name
    yield target, chain.dup
  end
end

# (b) set_callbacks
def set_callbacks(name, callbacks) # :nodoc:
  unless singleton_class.method_defined?(:__callbacks, false)
    self.__callbacks = __callbacks.dup
  end
  self.__callbacks[name.to_sym] = callbacks
  self.__callbacks
end
fujitamasashi255 commented 5 months ago

description

# module ActiveSupport
#   module Callbacks
#     extend Concern
#     included do
#       extend ActiveSupport::DescendantsTracker
#       class_attribute :__callbacks, instance_writer: false, default: {}
#     end
#     CALLBACK_FILTER_TYPES = [:before, :after, :around]
#
#     def run_callbacks
#
#     private
#
#     module Filters
#       class Before
#       class After
#       class Callback
#     module Conditionals
#     module CallTemplate
#     class CallbackSequence
#     class CallbackChain
#     module ClassMethods
#       def set_callback
#       def skip_callback
#       def reset_callbacks
#       def define_callbacks
#
#       protected
#
#       def get_callbacks
#       def set_callbacks

def run_callbacks(kind)
  callbacks = __callbacks[kind.to_sym] # kind は save, create など

  if callbacks.empty?
    yield if block_given?
  else
    env = Filters::Environment.new(self, false, nil)
    next_sequence = callbacks.compile

    # Common case: no 'around' callbacks defined
    if next_sequence.final?
      next_sequence.invoke_before(env)
      env.value = !env.halted && (!block_given? || yield)
      next_sequence.invoke_after(env)
      env.value
    else
      invoke_sequence = Proc.new do
        skipped = nil

        while true
          current = next_sequence
          current.invoke_before(env)
          if current.final?
            env.value = !env.halted && (!block_given? || yield)
          elsif current.skip?(env)
            (skipped ||= []) << current
            next_sequence = next_sequence.nested
            next
          else
            next_sequence = next_sequence.nested
            begin
              target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
              target.send(method, *arguments, &block)
            ensure
              next_sequence = current
            end
          end
          current.invoke_after(env)
          skipped.pop.invoke_after(env) while skipped&.first
          break env.value
        end
      end

      invoke_sequence.call
    end
  end
end
fujitamasashi255 commented 5 months ago

https://qiita.com/advent-calendar/2023/reading

Dockerfile

https://techracho.bpsinc.jp/hachi8833/2023_11_09/116843

debug: docker compose build --no-cache --progress=plain

電子署名

TS

Ruby

https://moneyforward-dev.jp/search?q=%E3%83%9E%E3%83%8D%E3%83%BC%E3%83%95%E3%82%A9%E3%83%AF%E3%83%BC%E3%83%89%E7%A4%BE%E5%86%85PR%E3%81%AB%E8%A6%8B%E3%82%89%E3%82%8C%E3%82%8BRuby%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

https://qiita.com/okuramasafumi/items/b52c9c9e5d3e7cdfa371#json%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AE%E4%B8%AD%E8%BA%AB

Ansible

https://zenn.dev/y_mrok/books/ansible-no-tsukaikata/viewer/chapter1

autoload

Open API

レプリケーション

https://mysql.sql55.com/sql/mysql-create-table-select.php#2

amazon aurora:

モデリング

Web API

AR

ActiveStorage

fujitamasashi255 commented 5 months ago

React ステート管理 比較考察

useState + バケツリレー

責務の観点

ステートの伝達に係る責務がステートの直接の使用者以外にも発生することです。図では、上からステートを受け取ってそのまま下に流しているコンポーネントたちがこれに相当します。

即物的な見方

まず、useState + バケツリレーはパフォーマンス上不利になる可能性があります。使用者までの途中のコンポーネントも含めて多くのコンポーネントが実際にpropsとしてステートを受け取るということは、(たとえReact.memoなどで再レンダリングを抑制していたとしても)ステートが変化した際にはそれらのコンポーネントが再レンダリングされることになります。これにより、実際に必要なよりも多くのコンポーネントがレンダリングされることになります。

また、リファクタリングの過程でステートの型や名前(propsの型や名前名前)が変わることも考えられます。その際、そのステートの型や名前をインターフェースに含んだコンポーネントが多ければそれだけ多くのコンポーネントを変更しなければなりません。これはいわゆる凝集度が低くなってしまっていることを表しています。

以上のことから、パフォーマンスやコードのメンテナンス性を重視する場合は、useState + バケツリレーは推奨されません。

useContextの使用

責務の観点

インターフェース(コンポーネントが受け取るprops)の観点で見ると、もはやこのステートはコンポーネントのpropsに現れません。途中のコンポーネントはもちろんのこと、使用者であるコンポーネントもステートをpropsではなくuseContextで受け取ります。このことから、ステートを使用することはもはやコンポーネントの責務ではなく、コンポーネントの内部処理の一部であると見なされます。

言い方を変えれば、context由来のステートは一種の外部ソースと見なされるということです。

つまり、contextから必要なステートを得るコンポーネントは、インターフェース上はたとえば外部のサーバーから情報をfetchするコンポーネントと似た振る舞いをするということです。問題点としては、このようにコンポーネントの内部実装の一環として外部ソースを取得する場合、テストのしやすさにやや難があることが挙げられます。

このことが気に入らない場合は、いわゆる「containerコンポーネントとpresentationalコンポーネント」のような概念を持ち出すことである程度解決できます。この場合、containerコンポーネントはどこからともなく(実際にはcontextから)ステートを持ってくるだけの薄いコンポーネントとなり、presentationalコンポーネントはcontainerコンポーネントからpropsで渡されたステートを描画するという責務を持つことになります。このように責務を分割することでテストが少しやりやすくなります。

即物的な見方

パフォーマンスの観点からは、useContextのほうがuseState + バケツリレーよりは有利です。なぜなら、useContextを使うことで、ステートが変わった際には本当にそのステートを使用しているコンポーネントのみが再レンダリングされるようになるからです。コンポーネントツリーの頂点と使用者の間にある中間コンポーネントは、useContextを使っていなければ再レンダリングされません1

しかし、コンポーネント間で共有されるステートが複雑化してくると、不満が出てくるでしょう。グローバルに使用されるステートが複数種類ある場合、それぞれで使用者も異なります。その場合、ステートの種類に応じて別々のProviderを用意しなければいけません。

まとめると、useState + useContextでグローバルなステート管理をする場合は、たくさんのコンテキストを管理しなければならないかパフォーマンスの低下かどちらかを受け入れなければならないということです。

fujitamasashi255 commented 5 months ago

普段コンポーネントを作るときに意識していることをまとめる

https://zenn.dev/ogakuzuko/scraps/1fd6da285612ce

fujitamasashi255 commented 5 months ago

https://ja.react.dev/learn

コンポーネントを純粋に保つ

副作用を引き起こせる場所

React では、副作用は通常、イベントハンドラの中に属します。イベントハンドラは、ボタンがクリックされたといった何らかのアクションが実行されたときに React が実行する関数です。イベントハンドラは、コンポーネントの「内側」で定義されているものではありますが、レンダーの「最中」に実行されるわけではありません! つまり、イベントハンドラは純粋である必要はありません。

いろいろ探してもあなたの副作用を書くのに適切なイベントハンドラがどうしても見つからない場合は、コンポーネントから返された JSX に useEffect 呼び出しを付加することで副作用を付随させることも可能です。これにより React に、その関数をレンダーの後(その時点なら副作用が許されます)で呼ぶように指示できます。ただしこれは最終手段であるべきです。

レンダーとコミット

https://ja.react.dev/learn/render-and-commit

あなたがレンダーをトリガした後、React はコンポーネントを呼び出して画面に表示する内容を把握します。「レンダー」とは、React がコンポーネントを呼び出すことです。

初回レンダー時、React はルート (root) コンポーネントを呼び出します。 次回以降のレンダーでは、state の更新によってレンダーがトリガされた関数コンポーネントを、React が呼び出します。 このプロセスは再帰的に発生します。更新されたコンポーネントが他のコンポーネントを返す場合、次にそのコンポーネントを React がレンダーし、そのコンポーネントも何かコンポーネントを返す場合、そのコンポーネントも次にレンダーし、といった具合に続きます。このプロセスは、ネストされたコンポーネントがなくなり、React が画面に表示されるべき内容を知り尽くすまで続きます。

更新されたコンポーネントがツリー内で非常に高い位置にある場合、その内部にネストされたすべてのコンポーネントを再レンダーするというデフォルトの挙動は、パフォーマンスにとって理想的ではありません。パフォーマンスの問題に遭遇した場合、パフォーマンスセクションで述べられているいくつかのオプトインによる解決方法があります。早まった最適化をしてしまってはいけません!

アクセシビリティ

https://developer.mozilla.org/ja/docs/Learn/Accessibility/HTML

デザインシステム

https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969