Open18

《スクラップ・リサイクラー》

Legokichi DuckscallionLegokichi Duckscallion

202x 年代に生きる上で認識を革めるべきこと

政治・経済・社会

  • 中国はいまや米国に匹敵する経済規模を持つ超大国であること
  • 日本はもはや世界第三位の経済大国ですらないこと
  • 日本の高齢化は負荷逆に進み今後若者はますます希少になること
  • 海外の物価が上がり続けているので外貨を稼がない限り海外旅行にいくことすら困難になること

コンピュータ・IT・AIoT

  • クラウド SaaS 化が進み、ローコードでますます大きな価値を生み出せるようになっていること
  • プログラミング言語やフレームワークに依存する技術者は世界一レベルの専門性を持たない限り生き残れないこと
  • リアル人生とネット人生という区分は時代錯誤も甚だしく、リアルとインターネットは融合するということ(IoT 含む)
  • AI学習のイテレーションを早く回して現実に適応するほど価値が生まれること
  • 人工知能(無能ではない) bot の作成が当たり前になること
  • 低速回線で Vim を使うよりも高速回線で Cloud Shell や vscode-online を使うほうが開発効率がよくなること
  • クラウドの寡占が進むことで(逆説的に)クライアントサイド技術への投資が進むこと
Legokichi DuckscallionLegokichi Duckscallion

モナドはテストできないから使うべきではない

async fn hoge(){
  let a = io1().await;
  let b = if ... {
     Some(io2(a).await)
  } else { None };
  let c = io3(b).await;
  Ok(c)
}

みたいなモナディックな関数はテストできない

fn hoge() -> impl Future<Outut=Result<_, _>> {
   io1().and_then(pure1).and_then(io2).and_then(pure2).and_then(io3)
}

のようなアプリカティブな形に書き下すべきである

すると

iot1, io2, io3, および pure1, pure2 はそれぞれ unit test が書けるようになる

use futures::Future;
use futures::FutureExt;
use futures::future::TryFutureExt;

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
    let d = source()
        .then(|o| futures::future::ready(pure1(o)))
        .and_then(|o| { unite(o, io1, io2).map(Ok) })
        .then(|o| futures::future::ready(pure2(o.unwrap())))
        .and_then(|o|{
            sink(o).map(Ok)
        })
        .then(|o| futures::future::ready(pure3(o.unwrap())))
        .await;
    let ret = source().await;
    let b = pure1(ret)?;
    let ret = unite(b, io1, io2).await;
    let c = pure2(ret)?;
    let ret = sink(c).await;
    let d = pure3(ret)?;    
    Ok(())
}

fn unite<L, R, L2, R2, FL, FR>(
    o: either::Either<L, R>,
    io1: impl FnOnce(L) -> FL,
    io2: impl FnOnce(R) -> FR,
) -> impl Future<Output=either::Either<L2, R2>,> 
where
    FL: Future<Output=L2>,
    FR: Future<Output=R2>,
{
    match o {
        either::Either::Left(o)=> 
            futures::future::Either::Left(
                io1(o)
                    .map(either::Either::<L2, R2>::Left)),
        either::Either::Right(o)=>
            futures::future::Either::Right(
                io2(o)
                    .map(either::Either::<L2, R2>::Right)),
    }
}

struct SourceRes{}
#[derive(thiserror::Error, Debug)]
#[error("")]
struct SourceError{}
fn source(
) -> impl Future<Output=Result<SourceRes, SourceError>> {
    futures::future::ready(Ok(SourceRes{}))
}

fn pure1(o: Result<SourceRes, SourceError>) -> Result<either::Either<Io1Req, Io2Req>, anyhow::Error> {
    o.map(|_| either::Either::Left(Io1Req{})).map_err(|_| anyhow::anyhow!(""))
}

struct Io1Req{}
struct Io1Res{}
#[derive(thiserror::Error, Debug)]
#[error("")]
struct Io1Error{}
fn io1(o: Io1Req) -> impl Future<Output=Result<Io1Res, Io1Error>> {
    futures::future::ready(Ok(Io1Res{}))
}

struct Io2Req{}
struct Io2Res{}
#[derive(thiserror::Error, Debug)]
#[error("")]
struct Io2Error{}
fn io2(o: Io2Req) -> impl Future<Output=Result<Io2Res, Io2Error>> {
    futures::future::ready(Ok(Io2Res{}))
}

fn pure2(o: either::Either<Result<Io1Res, Io1Error>, Result<Io2Res, Io2Error>>) -> Result<SinkReq, anyhow::Error> {
    match o {
        either::Either::Left(o) => o.map(|_| SinkReq{}).map_err(|_| anyhow::anyhow!("")),
        either::Either::Right(o) => Err(anyhow::anyhow!("")),
    }
}

struct SinkReq{}
struct SinkRes{}
#[derive(thiserror::Error, Debug)]
#[error("")]
struct SinkError{}
fn sink(o: SinkReq) -> impl Future<Output=Result<SinkRes, SinkError>> {
    futures::future::ready(Ok(SinkRes{}))
}

fn pure3(o: Result<SinkRes, SinkError>) -> Result<(), anyhow::Error> {
    o.map(|_| ()).map_err(|_| anyhow::anyhow!(""))
}

うーん

frunk の coproduct を使いつつ
(futureのthenを使わずに)独自型のメソッド呼び出しで関数合成っぽく書いていく

Context::new()
   .a()  // 実質 Into
   .b(opt) // io は Future
  .await? // Result<_, anyhow::Error>
  .c() // Copro!(A, B)
  .fold(hlist![ //条件分岐
    |o|async move{
      ...
      Ok(())
    },
    |o|async move{
       ...
       Ok(())
    },
  ])
   .await?
   .fin()
Legokichi DuckscallionLegokichi Duckscallion

info

libs

funcs

fn main() {
    use itertools::Itertools; // 0.10.1
    for a in 0..=1 {
        for b in 0..=1 {
            for c in 0..=1 {
                for d in 0..=1 {
                    println!("prmtv:{:?}", (a, b, c, d));
                }
            }
        }    
    }
    for item in (0..=1).cartesian_product(0..=1).cartesian_product(0..=1).cartesian_product(0..=1) {
        println!("prd2:{:?}", item);
    }
    for item in (1..=4).map(|_| 0..=1).multi_cartesian_product() {
        println!("prdm:{:?}", item);
    }
    for item in (0..=2).permutations(3) {
        println!("perm:{:?}", item);
    }
    for item in (0..=2).combinations(2) {
        println!("comb:{:?}", item);
    }
    for item in (0..=2).combinations_with_replacement(2) {
        println!("comb_r:{:?}", item);
    }
    let idx = vec![1,3,5,7].binary_search_by(|o|{ o.cmp(&3) });
    assert_eq!(idx, Ok(1));
    let idx = vec![1,3,5,7].binary_search_by(|o|{ o.cmp(&2) });
    assert_eq!(idx, Err(1));
    let idx = vec![1,3,5,7].binary_search_by(|o|{ o.cmp(&6) });
    assert_eq!(idx, Err(3));
    let target = 10;
    let kuji = vec![1,3,5,7];
    for item in (1..=4).map(|_| kuji.iter()).multi_cartesian_product() {
        if item.iter().copied().sum::<i32>() == target {
            println!("kujiprm:{:?}", item);
        }
    }
    let mut fin = false;
    for fst in kuji.iter().rev() {
        if fin { break; }
        let snd_acceptable = target - fst - 2;
        let _ = kuji.binary_search_by(|snd|{
            if fin { return std::cmp::Ordering::Equal; }
            // println!("{} <= {} | {}", snd, snd_acceptable, fst);
            if snd <= &snd_acceptable {
                let trd_acceptable = target - (fst + snd) - 1;
                let _ = kuji.binary_search_by(|trd|{
                    // if fin { return std::cmp::Ordering::Equal; }
                    // println!("{} <= {} | {}", trd, trd_acceptable, fst + snd);
                    if trd <= &trd_acceptable {
                        let fth = target - (fst + snd + trd);
                        if kuji.binary_search(&fth).is_ok() {
                            println!("kujibin:{:?}", (fst, snd, trd, fth));
                            fin = true;
                            return std::cmp::Ordering::Equal;
                        }
                    }
                    trd.cmp(&trd_acceptable)
                });
            }
            snd.cmp(&snd_acceptable)
        });
    }
    println!("kujibin:{:?}", fin);
    assert_eq!(vec![1,7,3,4].iter().copied().min(), Some(1));
    assert_eq!(vec![1,7,3,4].iter().copied().max(), Some(7));
    assert_eq!(vec![1.0,7.0,3.0,4.0_f32].iter().copied().reduce(f32::min), Some(1.0));
    assert_eq!(vec![1.0,7.0,3.0,4.0_f32].iter().copied().reduce(f32::max), Some(7.0));
    assert_eq!(vec![1,7,3,4].iter().copied().minmax().into_option(), Some((1, 7)));
    assert_eq!(vec![1.0,7.0,3.0,4.0_f32].iter().copied().minmax().into_option(), Some((1.0, 7.0)));
    assert_eq!((1..10).step_by(2).collect::<Vec<_>>(), vec![1,3,5,7,9]);
}

strucs

// AtCoder ABC 131 C - Anti-Division
fn main() {
    use num; // 0.4.0
    let a = 4;
    let b = 9;
    let c = 2;
    let d = 3;
    let ans = 2;
    assert_eq!(calc2(a,b,c,d), ans);
    let a = 314159265358979323_u64;
    let b = 846264338327950288_u64;
    let c = 419716939_u64;
    let d = 937510582_u64;
    let ans = 532105071133627368_u64;
    let ret = calc2(a,b,c,d);
    assert_eq!(ret, ans);
}
fn calc(a: u64, b: u64, c: u64, d: u64) -> u64 {
    let mut count = 0;
    for i in a..=b {
        if i % c != 0 && i % d != 0 { count += 1; }
    }
    count
}
fn calc2(a: u64, b: u64, c: u64, d: u64) -> u64 {
    dbg!(f(b, c, d)) - dbg!(f(a-1, c, d))
}
fn f(x: u64, c: u64, d: u64) -> u64 {
    let lcm = num::integer::lcm(c, d);
    x - x/c - x/d + x/lcm
}
Legokichi DuckscallionLegokichi Duckscallion
Legokichi DuckscallionLegokichi Duckscallion
  • sudo apt changelog vim - 更新履歴
  • sudo apt clean - deb パッケージの削除
  • sources.list- パッケージの取得元
  • apt.conf - apt の設定
  • preferences - man apt_preference
  • sudo apt install vim:arm6
Legokichi DuckscallionLegokichi Duckscallion

DI パターン

3 層レイヤードアーキテクチャを考える

IO <-> DomainLogic <-> Service

DIしない階層アーキテクチャの場合

依存関係はこう

IO <- DomainLogic <-  Service

型を書くとこう

struct IOA {}
impl IOA { fn new()-> Self{ .. } }
struct DomainLogicA { io_a: IOA }
impl DomainLogicA  { fn new()-> Self{ .. } }
struct ServiceA {dom_a: DomainLogicA}
impl ServiceA  { fn new()-> Self{ ...} }

DIする場合

コンストラクタパターン

依存関係の順番はこう

IO -> DomainLogic <-  Service

型を書くとこう

trait IOA {}
struct DomainLogicA { io_a: Arc<dyn IOA> }
impl DomainLogicA  { fn new(io_a: impl IOA)-> Self{ .. } }
struct ServiceA { dom_a: DomainLogicA }
impl ServiceA  { fn new(io_a: impl IOA)-> Self{ .. } }

Cake Pattern (Keen Pattern)

trait UserDao {...}
trait HaveUserDao {
  type UserDao: UserDao;
  fn user_dao(&self) -> Self::UserDao;
}
struct UserService<U>{U);
impl<U:UserDao> UserService<U> {
  pub fn get_user_by_id(&self, id: i32) -> Result<Option<User>> {
    self.0.find_user(id)
  }
}

Cake Pattern

trait UserDao {...}
struct UserService<U>{U);
impl<U: UserDao> UserService<U> {
  pub fn get_user_by_id(&self, id: i32) -> Result<Option<User>> {
    self.0.find_user(id)
  }
}

functional

// DI コンテキスト, 依存性注入はここでする
struct SrvACtx {
    lambda: Lambda,
    dynamodb: DynamoDb,
    logger: Logger,
}
// 引数
struct SrvAReq {
    hoge: String,
    huga: String
}
// 正常な返り値
struct SrvARes {}
// リトライしろ、等
struct SvcAErr {}
// anyhow::Error は事前条件が満たされなかった等の panic 相当の例外
async fn srv_a(ctx: SrvACtx, req: ServiceAReq) -> Result<Result<SvcARes, SvcAErr>, anyhow::Error> {
    todo!()
}

Tagless Final

Free Monad

todo

Legokichi DuckscallionLegokichi Duckscallion

syslog rsyslog journald 違い

syslog 用法

  • 通信プロトコル
  • ログフォーマット
  • ログ転送集約システム
  • linuxシステムの全体のログ

syslog 歴史

  • https://logstorage.com/case/syslog/
  • 1980 最初のソフトウェア(syslogd の原型)が作られる
  • 1998 syslog-ng 開発開始
  • 2001 syslog 実装が仕様として文書化された
  • 2004 rsyslog 開発開始
  • 2009 syslog の仕様が整理されマトモになった
  • 2010 最初の systemd リリース

syslog

  • 昔使われてたログ転送システム
  • デーモンのログをファイルに保存する
  • UDPで他のサーバに転送できる

syslogd

syslog-ng

rsyslog

systemd-journald

Legokichi DuckscallionLegokichi Duckscallion

PPPって何

Serial Line Internet Protocol

  • 1984 標準化
  • 何らかの通信回線(電話回線など)からインターネットにつなぐプロトコル
  • IP をもらうしくみ
  • 誤り訂正がない

Point-to-Point Protocol

  • 1992 SLIP の後継で作られた
  • 特にダイヤルアップ(電話)回線でインターネットにつなぐためにつかう
  • モデムを介してISPに電話して認証もらってIPをもらうプロトコル

PPPoE

  • 「(何らかの通信回線で)認証もらってIPをもらうプロトコル」の何らかの通信回線が Ethernet になった
  • ADSL時代に電話回線ごしに ISP と通信できるようになったが、ここで IP を振るのに使われるようになった
  • Ethernet 単体でも IP が扱えるが PPPの「認証もらってIPをもらうプロトコル」だけが生き残った
  • 光回線でもそのまま使われている

ADSL

  • 既存のアナログ電話回線でISPと通信するしくみ
  • IP をふるのに PPPoE を使った

ISDN

  • ADSL がアナログ電話回線をつかってたので電話回線をデジタル化したもの
  • 光ファイバーに負けた

IPv6 PPPoE

  • NTTフレッツ網(NGN) 経由でIPv6 を割り当てるプロトコル
  • NGNが整備されたことで ISDN は滅んだ

SORACOM の SIM ドングルで PPP を使う理由

  • SIMカードを使って携帯電話回線(3G,LTE,5G)から携帯電話にIPを振るのに使ってる

参考資料