※当サイトの記事には、広告・プロモーションが含まれます。

Rubyのmoduleでクラスインスタンス変数が定義されるのは辛過ぎるんだが...

gigazine.net

主にAI技術の発達に伴って、GoogleやMeta、Amazonなどのテクノロジー企業は相次いで大規模なデータセンターの建設を進めています。こうしたデータセンターの運営には大量の電力が必要であり、アメリカのネブラスカ州オマハではデータセンターの誘致によって電力需要が増加し、閉鎖予定だった石炭火力発電所の稼働を続けざるを得ない状況になっているとのことです。

GoogleとMetaのデータセンターが大量の電力を使うせいで石炭火力発電所の閉鎖が先延ばしになっている - GIGAZINE

⇧ とは言え、「原子力発電」にシフトすれば、「放射性廃棄物」の問題に変わるだけだから、打つ手なしな感じではある。

gigazine.net

AI開発団体のOpenAIと長期的なパートナーシップを締結しているMicrosoftは、自社のデータセンターでChatGPTなどのAIのトレーニングを行っています。しかし、アイオワ州ウェストデモインズのMicrosoftのデータセンターは、現地で干ばつが発生しているにもかかわらず、AIのトレーニングに大量の水を使っていたことが指摘されています。これを受けてMicrosoftは、未来のエネルギー源として注目されている「小型モジュール式原子炉」を利用してデータセンターに電力を供給しようと検討していることが報じられています。

Microsoftが干ばつ時でも水を吸い上げてAIの訓練に使っていたとの批判、一方でMicrosoftは小型原子炉をデータセンターの電力源として検討を開始 - GIGAZINE

⇧ と、Microsoftは「原子力発電」に比重を置くような感じなのかもしれないですが、環境破壊の問題については、結局、無責任に先延ばししてるだけなのは、競合他社と変わらないと...

そもそもクラスで定義できる変数の種類の全量が分かり辛い

例の如く、

docs.ruby-lang.org

⇧ 公式のドキュメントだと分からず...

で、「FAQ(Frequently Asked Questions)」を確認した感じでは、

www.ruby-lang.org

Are there class variables?

There are. A variable prefixed with two at signs (@@) is a class variable, accessible within both instance and class methods of the class.

https://www.ruby-lang.org/en/documentation/faq/8/

What is a class instance variable?

Here the example of the previous section rewritten using a class instance variable:

https://www.ruby-lang.org/en/documentation/faq/8/

What is the difference between a class and a module?

Modules are collections of methods and constants. They cannot generate instances. Classes may generate instances (objects), and have per-instance state (instance variables).

https://www.ruby-lang.org/en/documentation/faq/8/

⇧ 3つ存在するようで、

  1. class variable
  2. class instance variable
  3. instance variable

⇧ 上記のような感じになるっぽい。

ネットの情報を漁った感じ、

jq-jo.github.io

⇧ 上記サイト様がまとめて下さっている。

Rubyのmoduleでクラスインスタンス変数が定義されるのは辛過ぎるんだが...

で、「Oxidized」というライブラリにおいては、

github.com

https://github.com/ytti/oxidized/blob/master/lib/oxidized/core.rb

module Oxidized
  class << self
    def new(*args)
      Core.new args
    end
  end

  class Core
    class NoNodesFound < OxidizedError; end

    def initialize(_args)
      Oxidized.mgr = Manager.new
      Oxidized.hooks = HookManager.from_config(Oxidized.config)
      nodes = Nodes.new
      raise NoNodesFound, 'source returns no usable nodes' if nodes.empty?

      @worker = Worker.new nodes
      @need_reload = false

      # If we receive a SIGHUP, queue a reload of the state
      reload_proc = proc do
        @need_reload = true
      end
      Signals.register_signal('HUP', reload_proc)

      # Initialize REST API and webUI if requested
      if Oxidized.config.rest?
        begin
          require 'oxidized/web'
        rescue LoadError
          raise OxidizedError, 'oxidized-web not found: sudo gem install oxidized-web - \
          or disable web support by setting "rest: false" in your configuration'
        end
        @rest = API::Web.new nodes, Oxidized.config.rest
        @rest.run
      end
      run
    end

    private

    def reload
      Oxidized.logger.info("Reloading node list and log files")
      @worker.reload
      Oxidized.logger.reopen
      @need_reload = false
    end

    def run
      Oxidized.logger.debug "lib/oxidized/core.rb: Starting the worker..."
      loop do
        reload if @need_reload
        @worker.work
        sleep Config::SLEEP
      end
    end
  end
end    

github.com

https://github.com/ytti/oxidized/blob/master/lib/oxidized/config.rb

module Oxidized
  require 'asetus'
  class NoConfig < OxidizedError; end
  class InvalidConfig < OxidizedError; end

  class Config
    ROOT       = ENV['OXIDIZED_HOME'] || File.join(Dir.home, '.config', 'oxidized')
    CRASH      = File.join(ENV['OXIDIZED_LOGS'] || ROOT, 'crash')
    LOG        = File.join(ENV['OXIDIZED_LOGS'] || ROOT, 'logs')
    INPUT_DIR  = File.join Directory, %w[lib oxidized input]
    OUTPUT_DIR = File.join Directory, %w[lib oxidized output]
    MODEL_DIR  = File.join Directory, %w[lib oxidized model]
    SOURCE_DIR = File.join Directory, %w[lib oxidized source]
    HOOK_DIR   = File.join Directory, %w[lib oxidized hook]
    SLEEP      = 1

    def self.load(cmd_opts = {})
      usrdir = File.expand_path(cmd_opts[:home_dir] || Oxidized::Config::ROOT)
      cfgfile = cmd_opts[:config_file] || 'config'
      # configuration file with full path as a class instance variable
      @configfile = File.join(usrdir, cfgfile)
      asetus = Asetus.new(name: 'oxidized', load: false, key_to_s: true, usrdir: usrdir, cfgfile: cfgfile)
      Oxidized.asetus = asetus

      asetus.default.username      = 'username'
      asetus.default.password      = 'password'
      asetus.default.model         = 'junos'
      asetus.default.resolve_dns   = true # if false, don't resolve DNS to IP
      asetus.default.interval      = 3600
      asetus.default.use_syslog    = false
      asetus.default.debug         = false
      asetus.default.run_once      = false
      asetus.default.threads       = 30
      asetus.default.use_max_threads = false
      asetus.default.timeout       = 20
      asetus.default.retries       = 3
      asetus.default.prompt        = /^([\w.@-]+[#>]\s?)$/
      asetus.default.rest          = '127.0.0.1:8888' # or false to disable
      asetus.default.next_adds_job = false            # if true, /next adds job, so device is fetched immmeiately
      asetus.default.vars          = {}               # could be 'enable'=>'enablePW'
      asetus.default.groups        = {}               # group level configuration
      asetus.default.group_map     = {}               # map aliases of groups to names
      asetus.default.models        = {}               # model level configuration
      asetus.default.pid           = File.join(Oxidized::Config::ROOT, 'pid')

      asetus.default.crash.directory = File.join(Oxidized::Config::ROOT, 'crashes')
      asetus.default.crash.hostnames = false

      asetus.default.stats.history_size = 10
      asetus.default.input.default      = 'ssh, telnet'
      asetus.default.input.debug        = false # or String for session log file
      asetus.default.input.ssh.secure   = false # complain about changed certs
      asetus.default.input.ftp.passive  = true  # ftp passive mode
      asetus.default.input.utf8_encoded = true  # configuration is utf8 encoded or ascii-8bit

      asetus.default.output.default = 'file'  # file, git
      asetus.default.source.default = 'csv'   # csv, sql

      asetus.default.model_map = {
        'juniper' => 'junos',
        'cisco'   => 'ios'
      }

      begin
        asetus.load # load system+user configs, merge to Config.cfg
      rescue StandardError => e
        raise InvalidConfig, "Error loading config: #{e.message}"
      end

      raise NoConfig, "edit #{@configfile}" if asetus.create

      # override if comand line flag given
      asetus.cfg.debug = cmd_opts[:debug] if cmd_opts[:debug]

      asetus
    end

    class << self
      attr_reader :configfile
    end
  end

  class << self
    attr_accessor :mgr, :hooks
  end
end 

⇧ とあり、「module」が「class instance variable」を定義してらっしゃる...

そもそも、「class instance variable」なのに、「module」で定義できるってのがカオス過ぎるんだが...

そして、

www.rubydoc.info

⇧ 噛み合わないドキュメントたち...

何と言うか、「Ruby」に触れるのが更に嫌になってくるのだが、

docs.gitlab.com

Background

Rails somehow encourages people using modules and instance variables everywhere.

https://docs.gitlab.com/ee/development/module_with_instance_variables.html

⇧ 上記サイト様によりますと、「Ruby on Rails」だと「module」に「instance variable」を利用することを推奨しているとか...

所謂、

xtech.nikkei.com

⇧ 日本だと敬遠されがちな「保守・運用」を全く考慮しない感じっぽいですな。

海外だと、役割分担が明確になってるからして、

  1. 開発
  2. 保守・運用

が分かれていて、「保守・運用」を一切気にせず「開発」できるってことなのかね?

でも、「DevOps」とかって概念の発祥って海外だったような...

とりあえず、「Ruby」は大規模開発には向かなそうね...

毎度モヤモヤ感が半端ない…

今回はこのへんで。