- ã¯ããã«
- TL;DR
- gokart ã¨ã¯
- luigi.Config ã®å©ç¨æ¹æ³
- gokart.SerializableParameter ãå©ç¨ãããã©ã¡ã¼ã¿ã¼ã®å ±éå
- ã¾ã¨ã
- We are hiring!
ã¯ããã«
ãã¡ãã¯ã¨ã ã¹ãªã¼ Advent Calendar 2024 3 æ¥ç®ã®è¨äºã«ãªãã¾ãã AIã»æ©æ¢°å¦ç¿ãã¼ã ã®å±±æ¬(@hiro_o918)ã§ãã
ä»å㯠Python 3.8 ããå°å ¥ããã Protocol ãå©ç¨ãã¦ãgokart ã§ä»»æã®ãã©ã¡ã¼ã¿ã¼ãå©ç¨ã§ããããã«æ©è½æ¡å¼µãè¡ã£ã話ããã¾ãã
TL;DR
ãã®è¨äºã§ã¯æ¬¡ã®ããã«ä»»æã®ãã©ã¡ã¼ã¿ã¼ãªãã¸ã§ã¯ãã gokart ã®ãã©ã¡ã¼ã¿ã¼ã¨ãã¦å©ç¨ããæ¹æ³ãç´¹ä»ãã¾ãã
class AddTask(gokart.TaskOnKart): config: ComputeParams = gokart.SerializableParameter(object_type=ComputeParams) def run(self): self.dump(self.config.a + self.config.b) config = ComputeParams(a=1, b=2) gokart.build(AddTask(config=config))
å°ãé·ããªã£ã¦ãã¾ã£ãã®ã§ãæ°ã«ãªãå 容ã«å¿ãã¦èªã¿é²ãã¦ããã ããã°å¹¸ãã§ãã
- æ¬æ©è½ãä½ãä¸ã§ã®åæã¨ãªã gokart ã®æ©è½ã課é¡æããæ°ã«ãªãæ¹:
- ãã®ã¾ã¾èªã¿é²ãã¦ãã ãã
- gokart ããã§ã«å©ç¨ãã¦ãã¦ç«¯çã«å©ç¨æ¹æ³ãç¥ãããæ¹:
- ä»çµã¿ã¨åããã¦å©ç¨æ¹æ³ãç¥ãããæ¹:
ãªããä»åã®æ©è½è¿½å ã® PR ã¯æ¬¡ã®ãªã³ã¯ãã確èªã§ããgokart v1.8.0 ããå©ç¨å¯è½ã§ãã
gokart ã¨ã¯
gokart ã¯ãã¨ã ã¹ãªã¼ãéçºããæ©æ¢°å¦ç¿ãã¤ãã©ã¤ã³ãã¼ã«ã§ãã Spotify 社ãéçºãã luigi ãã©ãããã¦æ©è½ã追å ãã¦ãã¾ãã
ã¡ããã© Advent Calender 2 æ¥ç®ã§æ± å¶ãããæ¸ãããè¨äºã§ããã®ç¹å¾´ãç´¹ä»ããã¦ããã®ã§ããã²ã覧ãã ããã
ã¾ããæ¬é¡ã®ä»åã®æ©è½è¿½å ã®å 容ã«è§¦ããåã«ãé¢é£ãã gokart ã®ç¹å¾´ã«ã¤ãã¦ç°¡åã«è§¦ãã¦ããã¾ãã
gokart ã«ããããã£ãã·ã¥ã®ä»çµã¿
å ã»ã©ã®è¨äºã®ã解決 3: å¿ è¦ãªé¨åã ããéç®ãã¦åå®è¡ãã«ããã gokart ã®ç¹å¾´ã¨ãã¦ãå ¥åãã©ã¡ã¼ã¿ã¼ã«å¯¾ãã¦ãã®ã¿ã¹ã¯ã®çµæããã£ãã·ã¥ã¨ãã¦ä¿åããã¨ããæ©è½ãããã¾ã*1ã
ä¾ã¨ãã¦ã次ã®ãã㪠2 ã¤ã® int
ãã©ã¡ã¼ã¿ã¼ãåãã¦ããã®åãè¨ç®ããã¿ã¹ã¯ãèãã¾ãã
import gokart import luigi class AddTask(gokart.TaskOnKart[int]): a: int = luigi.IntParameter() b: int = luigi.IntParameter() def run(self): self.dump(self.a + self.b)
gokart 㯠a
㨠b
ã®ãã©ã¡ã¼ã¿ã¼ã®çµã¿åããã«å¯¾ãã¦ããã®çµæããã£ãã·ã¥ã¨ãã¦ä¿åãã¾ãã
ä¾ãã°ãa=1
, b=1
ã¨ãããã©ã¡ã¼ã¿ã¼ã®çµã¿åãããéå»ã«å®è¡ãããã¨ãããå ´åãå度 run
ãå®è¡ãããã¨ãªããã£ãã·ã¥ãã 2
(1+1
) ã¨ããçµæãåå¾ãã¾ãã
ãã®æ©è½ã¯ãå
¥åãã©ã¡ã¼ã¿ã¼ã«å¯¾ãã¦ããã¿ã¹ã¯ã®çµæã¯åªçã§ããã¨ããåæã«ç«ã£ã¦ãããçµæã®åå©ç¨ã«ãã£ã¦å¹çã®è¯ãéçºä½é¨ãæä¾ã§ãã¾ãã
ã¾ããåªçãªå¦çãè¨è¿°ããåå¦ãåãã®ã¯ã³ã¼ãã®ä¿å®æ§ãåä¸ãããä¸ã§ãé常ã«æç¨ã§ã*2ã
ãªããã¿ã¹ã¯ã«åãè¨è¿°ããæ¹æ³ã¯æè¿è¿½å ãããæ©è½ã§ã以ä¸ã®è¨äºã§è©³ããç´¹ä»ããã¦ãã¾ãã www.m3tech.blog åå®å ¨ãªã³ã¼ããæ¸ããã¨ãã§ããã³ã¼ãã®ä¿å®æ§ãåä¸ããããã¨ãã§ããã®ã§ããã²æ´»ç¨ãã¦ã¿ã¦ãã ããã
gokart ã«ããããã©ã¡ã¼ã¿ã¼ã®åå©ç¨ã®ä»çµã¿
次ã«ãåããã©ã¡ã¼ã¿ã¼ãè¤æ°ç®æã§åå©ç¨ããä»çµã¿ã«ã¤ãã¦è§¦ãã¦ããã¾ãã
gokartï¼luigiï¼ã§ã¯ãã©ã¡ã¼ã¿ã¼å
±éåã®ä»çµã¿ã¨ã㦠luigi.Config
ã¨ããæ©è½ãæä¾ãã¦ãã¾ãã
次㮠luigi ã®ãã¼ã¸ã«ãã©ã¡ã¼ã¿ã¼å
±éåã®ãã¯ããã¯ã詳ããæ¸ããã¦ãã¾ãã
luigi.Config
ã®æ¸ãæ¹ã¨ãã¦ã¯æ¬¡ã®ããã«ãªãã¾ãã
class ComputeParams(luigi.Config): a: int = luigi.IntParameter() b: int = luigi.IntParameter()
Config ã¯ã©ã¹ã®å®ç¾©ã®æ¹æ³ã¯æ¯è¼çç´æçãªã®ã§ãããå©ç¨ããéã®ã¯ã»ãå°ããããä»åã®è¨äºã®ä¸»é¡ã«ãé¢é£ãã¦ããã®ã§ã次ã®ç« ã§è©³ãã説æãã¦ããã¾ãã
luigi.Config
ã®å©ç¨æ¹æ³
ããã§ã¯ãluigi.Config
ã使ã£ããã©ã¡ã¼ã¿ã¼ã®å
±éåã®æ¹æ³ã«ã¤ãã¦è©³ãã触ããä»åã®æ©è½ãå®è£
ããã«å½ãã£ã¦æããç§ã®èª²é¡æãå
±æãã¦ããã¾ãã
run ã®ä¸ã§ã°ãã¼ãã«ãªãã©ã¡ã¼ã¿ã¼ã¨ãã¦å¼ã³åºãæ¹æ³
ã¾ãã¯ãConfig ãã°ãã¼ãã«ãªãã©ã¡ã¼ã¿ã¼ã¨ãã¦å¼ã³åºãæ¹æ³ã«ã¤ãã¦èª¬æãã¾ãã
å ·ä½çãªè¨å®ä¾
lugi.Config
ã§å®ç¾©ããã°ãã¼ãã«ãªãã©ã¡ã¼ã¿ã¼ã«å¯¾ãã¦ã¯ãluigi ã®èª¬æã«ãããéãã次ã®ãããªè¨å®ãã¡ã¤ã«ããå¤æ°ãå²ãå½ã¦ããã¨ãã§ãã¾ãã
[ComputeParams] a=1 b=2
ãã®ä¸ã§ãrun
ã®ä¸ã§å¼ã³åºããã¨ã§å¤æ°ã¸ã®ã¢ã¯ã»ã¹ãå¯è½ã§ãã
class ComputeParams(luigi.Config): a: int = luigi.IntParameter() b: int = luigi.IntParameter() class AddTask(gokart.TaskOnKart[int]): def run(self): config = ComputeParams() self.dump(config.a + config.b) class MulTask(gokart.TaskOnKart[int]): def run(self): config = ComputeParams() self.dump(config.a * config.b) # å¦çã®å®è¡ gokart.build(AddTask()) gokart.build(MulTask())
課é¡
ä¸è¨ã®æ¹æ³ã¯ããã©ã¡ã¼ã¿ã¼ã®å ±éåã¨ãã¦æç¨ã«è¦ãã¾ãã 2 ç¹èª²é¡ãããã¾ãã
- run å
ã§çæããã Config ã¯ãã£ãã·ã¥ãçæããå
¥åå¤ã¨ãã¦æ±ãããªã
- gokart ã«ããããã£ãã·ã¥ã®ä»çµã¿ã§èª¬æããããã«ãgokart ã¯å ¥åãã©ã¡ã¼ã¿ã¼ã«å¯¾ãã¦ãã®ã¿ã¹ã¯ã®çµæããã£ãã·ã¥ã¨ãã¦ä¿åãã¾ãã
- ããããªãããä¸è¨ã®æ¹æ³ã§ã¯ Config ã¯ããã¾ã§ã¿ã¹ã¯å
ã®ãã¼ã«ã«å¤æ°ã¨ãã¦æ±ãããããããã£ãã·ã¥ã®çæã«ã¯å©ç¨ããã¾ããã
- è¨ãæããã¨
a
ã¨b
ã®å¤ãå¤ãã£ã¦ããã¿ã¹ã¯ã®åå®è¡ã¯è¡ããã¾ããã - ã¿ã¹ã¯ã®çµæã«å½±é¿ããªããã©ã¡ã¼ã¿ã¼ãªãåé¡ããã¾ããããããã§ã¯ãªãå ´åã¯è´å½çãªåé¡ã«ãªãã¾ãã
- è¨ãæããã¨
- è¨å®ãã¡ã¤ã«ããèªã¿è¾¼ãã§ããã¨ããæ
å ±ãæ示ããã¦ããªã
- æ
£ç¿ã¨è¨ãããã°ããã¾ã§ã§ãããã³ã³ã¹ãã©ã¯ã¿ã
ComputeParams
ã¯ã©ã¹ã§è¨å®ãã¡ã¤ã«ããèªã¿è¾¼ãã§ããã¨ããæ å ±ãæ示ããã¦ãããããã¼ã¿ã®æµãããããã«ããã§ãã
- æ
£ç¿ã¨è¨ãããã°ããã¾ã§ã§ãããã³ã³ã¹ãã©ã¯ã¿ã
ç¶æ¿ã§ãã©ã¡ã¼ã¿ã¼ãå ±éåããæ¹æ³
次ã«ãç¶æ¿ãå©ç¨ãã¦ãã©ã¡ã¼ã¿ã¼ãå ±éåããæ¹æ³ã«ã¤ãã¦èª¬æãã¾ãã
å ·ä½çãªè¨å®ä¾
次ã®ããã« luigi.Config
ãã¿ã¹ã¯ããç¶æ¿ãããã¨ã«ãã£ã¦ããã©ã¡ã¼ã¿ã¼ãå
±éåã§ãã¾ãã
class ComputeParams(luigi.Config): a: int = luigi.IntParameter() b: int = luigi.IntParameter() class AddTask(gokart.TaskOnKart[int], ComputeParams): def run(self): self.dump(self.a + self.b) class MulTask(gokart.TaskOnKart[int], ComputeParams): def run(self): self.dump(self.a * self.b) # å¦çã®å®è¡ config = ComputeParams() gokart.build(AddTask(a=config.a, b=config.b)) gokart.build(MulTask(a=config.a, b=config.b))
ãã®è¨å®ã®å ´åã¯ãã¿ã¹ã¯ã®ãã©ã¡ã¼ã¿ã¼ã¨ã㦠a
㨠b
ãèªèãããããããã£ãã·ã¥ã®çæã«ãå©ç¨ã§ãã¾ãã
課é¡
ä¸è¨ã®æ¹æ³ã§ããã£ãã·ã¥ã«å©ç¨å¯è½ãªãã©ã¡ã¼ã¿ã¼ã®å ±éåã¯å®ç¾ã§ãã¾ãããã次ã®ãããªèª²é¡ãããã¾ãã
- ç¶æ¿ãæ
å ±ã¨ãã¦ãã¤ã¸ã¼
- åç´ã«ãã©ã¡ã¼ã¿ã¼ã®éåãå ±éåãã¦æ¸¡ããã¨ãç®çã§ããã®ã«å¯¾ãã¦ãç¶æ¿ã¯ããé度ãªè¦æ±ã«æãã
- å¤æ°ã¨ãã¦ã¯ãã©ããã«æ¸¡ããã¨ã«ãªã
gokart.build
ã®é¨åãè¦ãã¨ãa
ã¨b
ããã©ããã«æ¸¡ããã¦ãããã¨ããããã¾ã- æ¬æ¥
ComputeParams
ã¨ããååä»ãã®ç²åº¦ã§ãã©ã¡ã¼ã¿ã¼ãæ±ãããã®ã«ãåã ã®ãã©ã¡ã¼ã¿ã¼ãæèããã³ã¼ããæ¸ãå¿ è¦ãããã¾ã
- æ¬æ¥
ãªããluigi.Config
ãç¶æ¿ãé¿ããæ¹æ³ã¨ãã¦ãluigi ã§ã¯ããã®è¨è¿°ã§ãinherits
㨠requires
ãç¨ãããã©ã¡ã¼ã¿ã¼ãå
±éåããæ¹æ³ãææ¡ããã¦ãã¾ãã
ããããªãããç§ã¨ãã¦ã¯åç´ã«ã³ã³ã¹ãã©ã¯ã¿ã«æ¸¡ãå¤æ°ã»ãããæ±ããã¨ã ãã«ãluigi åºæã®æ©è½ã«å¤§ããä¾åããã¿ã¹ã¯ãã®ãã®ã®è¨è¨ã«å½±é¿ãä¸ãããã¨ã¯é¿ãããã¨èãã¾ããã
gokart.SerializableParameter
ãå©ç¨ãããã©ã¡ã¼ã¿ã¼ã®å
±éå
åç½®ããé·ããªãã¾ãããããããããä»ååãçµãã ãã¨ã®æ¬é¡ã§ãã
ç®æãã¹ããã©ã¡ã¼ã¿ã¼ã®å ±éåæ¹æ³
ä¸è¨ã®èª²é¡ãè¸ã¾ãã¦ãã¾ãã¯ç§ã®ä¸ã§ã®ç®æãã¹ããã©ã¡ã¼ã¿ã¼ã®å ±éåæ¹æ³ãèãã¦ã¿ã¾ããã
AddTask(config=config)
ã®ããã« Config å¤æ°ãã¾ã¨ã¾ãã¨ãã¦ã³ã³ã¹ãã©ã¯ã¿ã«æ¸¡ãããã¨- ãã©ã¡ã¼ã¿ã¼ããã¹ããã¦ç®¡çã§ãããã¨
- ãã©ãããªãã©ã¡ã¼ã¿ã¼ã§ã¯ãªããæ¨æ§é çã«ãã©ã¡ã¼ã¿ã¼ãæ±ãããã¨
- ç¶æ¿ãªã©ãç¨ãã¦ã¿ã¹ã¯ã®è¨è¨ãå¤ããå¿
è¦ããªããã¨
- ãã©ã¡ã¼ã¿ã¼ã®è²¬åã¯ãã©ã¡ã¼ã¿ã¼ã§éãã¦ãããã¨
ãã®ãããªè¦ä»¶ãæºããããã«ãgokart.SerializableParameter
ã¨ãããã©ã¡ã¼ã¿ã¼ã¯ã©ã¹ãä½æãã¾ããã
次ã§ããã®å
·ä½çãªå©ç¨æ¹æ³ã«ã¤ãã¦èª¬æãã¦ããã¾ãã
gokart.SerializableParameter
ã®ä½¿ãæ¹
次ã«ç¤ºãã®ã¯ãgokart.SerializableParameter
ãå©ç¨ãããã©ã¡ã¼ã¿ã¼ã®å
±éåã®å
·ä½ä¾ã§ãã
import json from dataclasses import asdict, dataclass import gokart @dataclass(frozen=True) class ComputeParams: a: int b: int def gokart_serialize(self) -> str: """ãã©ã¡ã¼ã¿ã¼ã¨ãã¦ã®ããã·ã¥ãä½ãããã« str ã«å¤æããé¢æ°ãå®è£ ãã ãã ã deserialize å¯è½ãªæååã§ããå¿ è¦ã¯ãªã """ return json.dumps(asdict(self)) @classmethod def gokart_deserialize(cls, s: str) -> 'ComputeParams': """CLI ããã®å ¥åããã¼ã¹ããé¢æ°ãå®è£ ãã""" return cls(**json.loads(s)) class AddTask(gokart.TaskOnKart): config: ComputeParams = gokart.SerializableParameter(object_type=ComputeParams) def run(self): self.dump(self.config.a + self.config.b) class MulTask(gokart.TaskOnKart): config: ComputeParams = gokart.SerializableParameter(object_type=ComputeParams) def run(self): self.dump(self.config.a * self.config.b) config = ComputeParams(a=1, b=2) gokart.build(AddTask(config=config)) gokart.build(MulTask(config=config))
ãã®ä¾ãè¦ãã¨ãåè¿°ããç®æãã¹ããã©ã¡ã¼ã¿ã¼ã®å ±éåæ¹æ³ãæºããã¦ãããã¨ããããã¾ãã
ä»åã®ä¾ã§ã¯ãã©ã¡ã¼ã¿ã¼ã®ãã¹ãã¯è¡ã£ã¦ã¯ãã¾ãããããããè¡ãããã®æè¡ä¸ã®å¶ç´ã¯ããã¾ããã
å©ç¨ä¸ãã¢ã¨ãªãç¹ã¯ããã©ã¡ã¼ã¿ã¼ã¯ã©ã¹ã§ãã ComputeParams
ã次㮠2 ã¤ã®ã¡ã½ãããå®è£
ãã¦ãããã¨ã®ã¿ã§ãã
gokart_serialize
- ãã©ã¡ã¼ã¿ã¼ã¨ãã¦ã®ããã·ã¥ãä½ãããã«
str
ã«å¤æããé¢æ°ã®å®è£
- ãã©ã¡ã¼ã¿ã¼ã¨ãã¦ã®ããã·ã¥ãä½ãããã«
gokart_deserialize
- CLI ããã®å ¥åããã¼ã¹ããé¢æ°ã®å®è£
ä¾ã§ã¯ @dataclass
ãå©ç¨ãã¦ãã¾ãããããã¯è¨å®ãã¼ã¿ãæ±ããããã¨ããçç±ã§é¸ãã ã«ããããä»»æã®ã¯ã©ã¹ãå©ç¨ã§ãã¾ãã
gokart.SerializableParameter
ã®ä»çµã¿
gokart.SerializableParameter
ã®å®è£
ãè¦ãªãããå
é¨ã®ä»çµã¿ã«ã¤ãã¦èª¬æãã¦ããã¾ãã
ã³ã¼ãã¯å®éã®ãã®ããä¸é¨æç²ãããã®ã§ãã
from typing import Generic, TypeVar, Protocol T = TypeVar('T') class Serializable(Protocol): def gokart_serialize(self) -> str: ... @classmethod def gokart_deserialize(cls: type[T], s: str) -> T: ... S = TypeVar('S', bound=Serializable) class SerializableParameter(luigi.Parameter, Generic[S]): def __init__(self, object_type: type[S], *args, **kwargs): ...
gokart.SerializableParameter
ã§ã¯ãã³ã³ã¹ãã©ã¯ã¿ã®å¼æ°ã§ãã object_type
ã« Serializable
ã¨ãã Protocol ãæºãããã¯ã©ã¹ãæå®ãããã¨ãæå¾
ãã¦ãã¾ãã
Protocol ã¯ãPython 3.8 ããå°å
¥ãããåãã³ãã® 1 ã¤ã§ãããã¯ã©ã¹ãç¹å®ã®ã¡ã½ãããæã£ã¦ãããã¨ãä¿è¨¼ããããã«å©ç¨ããã¾ãã
Go è¨èªã® Interface ã Rust ã® Trait ã«è¿ãæ¦å¿µã§ãæ示çãªç¶æ¿ãããã«ãããã¯ã©ã¹ãç¹å®ã®ã¡ã½ãããæã£ã¦ãããã¨ãä¿è¨¼ããããã®æ©è½ã§ãã
Python ã®æ¢åã®æ©è½ã¨ãã¦ã¯ãabc.ABC
ãããã¾ãããä¸è¦ãªç¶æ¿ãé¿ãããã¨ãã§ãããã Protocol ãå©ç¨ãããã¨ãå人çã«ã¯å¥½ã¾ããã§ãã
ãã¡ãããåãå¦çã®å
±éåã®ããã«ç¶æ¿ãå©ç¨ããå ´é¢ã¯åºã¦ããã¨æãã¾ããããã®æ±ºå®ãã¦ã¼ã¶ã¼ã«å§ãããã¨ãã§ããã®ã¯ Protocol ã®å©ç¹ã ã¨æãã¾ãã
ã¿ã¹ã¯ã®ãã©ã¡ã¼ã¿ã¼ã¨ãã¦æ±ããããæ©è½ããConfig ãªãã¸ã§ã¯ãå´ã®å®è£ ã«å ¨ã¦æ¼ãä»ãããã¨ãã§ããããã ã¦ã¼ã¶ã¼ã¯ä»»æã® Config ãªãã¸ã§ã¯ããå©ç¨ã§ããããã«ãªãã¾ããã
Tips: ä¸é¨ã®ãã©ã¡ã¼ã¿ã¼ããã£ãã·ã¥ã®ãã¼ã«å«ããªãæ¹æ³
æå¾ã«ãgokart.SerializableParameter
éã«ãä¸é¨ã®ãã©ã¡ã¼ã¿ã¼ããã£ãã·ã¥ã®ãã¼ã«å«ããªãæ¹æ³ã«ã¤ãã¦èª¬æãã¾ãã
ä¾ãã°ã次ã®ãã㪠token
ã®å¤æ´ã§ã¿ã¹ã¯ã®åå®è¡ã¯ããããªãããversion
ã®å¤æ´ã§åå®è¡ãããã¨ãã APIConfig
ãããã¨ãã¾ãã
@dataclass(frozen=True) class APIConfig: version: str token: str
ãã®å ´åã§ã¯æ¬¡ã®ããã« gokart_serialize
ãå®è£
ãããã¨ã§ãtoken
ããã£ãã·ã¥ã®ãã¼ã«å«ããªãããã«ã§ãã¾ãã
@dataclass(frozen=True) class APIConfig: version: str token: str def gokart_serialize(self) -> str: return json.dumps({'version': self.version})
ããã¯ããã¾ã§ gokart_serialize
ããã£ãã·ã¥ãã¼ãç®åºããéã«å©ç¨ãããé¢æ°ã§ããããã§ãã
ããã«ãã token
ã®å¤æ´ã§ã¿ã¹ã¯ã®åå®è¡ãè¡ãããªãããã«ã§ãã¾ãã
ã¾ã¨ã
ä»åã¯ãPython ã® Protocol ãå©ç¨ã㦠gokart ã®ã¿ã¹ã¯ã§ä»»æã®ãã©ã¡ã¼ã¿ã¼ãå©ç¨ã§ããããã«ããæ©è½ã追å ãã話ããã¾ããã ã¾ãããã®æ©è½ã追å ããã«è³ã£ããæ¢åæ©è½ã®èæ¯ã課é¡æã«ã¤ãã¦ã触ãã¾ããã ä»åã®æ©è½ããã¼ã¹ã«ãããã¨ã§å¥½ããªã©ã¤ãã©ãªã§ãã Pydantic ãè¨å®ãªãã¸ã§ã¯ãã¨ãã¦å©ç¨ã§ããããã«ãªãããã ããããã® gokart ã®å©ç¨ããã楽ãããªãã¨æãã¦ãã¾ãã
gokart å¨ãã®è¨å®å ±éåã§æ©ãã äºããã人ã¾ã㯠Protocol ãå©ç¨ããè¨è¨ã«èå³ããã人ã«ã¨ã£ã¦åèã«ãªãã°å¹¸ãã§ãã
We are hiring!
ã¨ã ã¹ãªã¼ã§ã¯èªç¤¾ã§éçºãã¦ãã OSS ã§ãã gokart ãæ´»ç¨ãã¦ã100 ãè¶ ãããã¤ã¯ããµã¼ãã¹ãéç¨ãã¦ãã¾ãã å¤ãã®å ´é¢ã§ä½¿ããã¦ãããã¬ã¼ã ã¯ã¼ã¯ã§ããä¸æ¹ã§ãèªç¤¾ OSS ã§ããããèªåãåãå ¥ãããæ©è½ã¯ã¡ã³ãã¼ã¨å¯ã«è°è«ããªããã¬ã·ã¬ã·å¤æ´ãå ãããã¨ãã§ããç°å¢ã§ãã ç©æ¥µæ¡ç¨ä¸ãªã®ã§å°ãã§ãæ°ã«ãªãæ¹ã¯ããå¿åã»ã«ã¸ã¥ã¢ã«é¢è«ããå¾ ã¡ãã¦ããã¾ãï¼
ã¨ã³ã¸ãã¢æ¡ç¨ãã¼ã¸ã¯ãã¡ã
ã«ã¸ã¥ã¢ã«é¢è«ããæ°è»½ã«ã©ãã
ã¤ã³ã¿ã¼ã³ã常æåéãã¦ãã¾ã
*1:ããã¯ã©ããã¼å ã® luigi ã§ãæä¾ããã¦ããæ©è½ã§ãã
*2:å¤é¨ãã¼ã¿ãåå¾ããé¨åãªã©ãåªçã§ã¯ãªãå¦çã®å ´åã¯ããã®é¨åã®ã¿ãã¿ã¹ã¯ã¨ãã¦åãåºãã¦ãå®è¡æå»ããã©ã¡ã¼ã¿ã¼ãä»ä¸ãããã¨ã§å¼·å¶çã«å ¥åå¤ãä¸è´ããªãããã«ãã工夫ãã¦ãã¾ãã