Customizing Claude Code Configuration Based on everything-claude-code
This article was written by Claude Code.
I created a customized Claude Code configuration (dotfiles repository) based on everything-claude-code, reflecting my own technical philosophy. Key points are:
- Agents don't auto-inherit Skills/Rules — Established design principles based on this discovery
- Purpose-based Skill separation — Separating generic TypeScript patterns from framework-specific ones
- Codifying technical convictions — API idempotency, DB consistency, structured logging, Makefile
- Continuous Learning developed independently in a separate repository
1. Introduction
everything-claude-code is a Claude Code configuration collection by Affaan, an Anthropic hackathon winner. It provides Rules, Skills, Agents, and Commands refined through over 10 months of real-world use. The systematic four-layer design, original features like Continuous Learning and Skill Creator — this is pioneering work that elevated Claude Code usage to the next level, and I have deep respect for it.
This article describes the process and design decisions behind creating my customized version, building on this repository while reflecting my own technical philosophy.
2. Design Customizations
2.1 Roles of Rules / Skills / Agents
While working with everything-claude-code as a reference, I made an important discovery during actual use.
Discovery: Agents don't auto-inherit Skills/Rules
The Claude Code official documentation states:
Subagents receive only this system prompt (plus basic environment details like working directory), not the full Claude Code system prompt.
Subagents don't inherit skills from the parent conversation; you must list them explicitly.
In other words, Agents don't automatically inherit either Rules (included in the system prompt) or Skills from the main session. The solution is to explicitly specify them using the skills: field in the Agent's frontmatter (details).
Role separation principles
| Element | Characteristic | Content |
|---|---|---|
| Rules | Always loaded | Lightweight, principles only, language-agnostic |
| Skills | Conditionally loaded | Implementation details OK, framework-specific |
| Agents | Explicitly inherit Skills | Workflow and decision criteria |
Content needed in both the main session and Agents should be placed in Skills, not Rules.
2.2 Context Efficiency
Don't write "things Claude already knows" in Skills. Write only policies/directions and information requiring context7 or web search.
Example: A Python skill should include "use uv for new projects" but not uv command details. Claude already knows uv, so conveying the policy alone is sufficient (details).
2.3 Skill Separation Strategy
everything-claude-code uses a language-based directory structure (rules/typescript/), but my customized version uses purpose-based separation.
Since TypeScript is used across CDK, React, and Vue, I extracted generic patterns into typescript-patterns and separated framework-specific patterns into individual Skills. Only the necessary combinations are loaded, improving context efficiency (details).
3. Technical Convictions
I added Rules/Skills reflecting my own technical philosophy that aren't present in everything-claude-code.
3.1 API Design: Idempotency at the Center
"POST = create, PUT = update" is wrong. PUT means "create or replace a resource at a specific URI," and the essence of HTTP methods is whether they are idempotent (details).
3.2 Database Design: Caching is a Bad Habit
The reason to use RDBMS is data consistency. Carelessly introducing caching or combining NoSQL in ways that prevent transactions defeats the purpose. Before considering cache, you should analyze queries with EXPLAIN, add indexes, and optimize schemas (details).
3.3 Structured Logging
Structured logging (JSON, logfmt, etc.) is mandatory for server-side code. By outputting in a machine-parseable format with timestamp, level, message, and requestId — instead of console.log('user logged in') — you enable analysis with jq/Datadog/CloudWatch Logs Insights and per-request tracing.
3.4 Makefile: The Ultimate Handover Document
A Makefile is not just a build tool — it's a project's "handover document." make help serves as documentation, make setup handles environment setup, and make check runs pre-PR checks. It functions as a single, language-agnostic interface (details).
4. Features Not Adopted from everything-claude-code
4.1 Continuous Learning v2
everything-claude-code includes a feature for "automatic learning from session patterns," but I didn't adopt it.
Reason: I'm developing it independently in a separate repository. I want to customize it to my own requirements, so I'm building it as a standalone project.
4.2 Skill Creator
I also didn't adopt the feature that auto-generates skills from Git history (/skill-create command and GitHub App).
Reason: I improve through real-time feedback during development. I keep Claude Code running on my dotfiles repository in a separate tab while developing. When I notice something about Claude's behavior, I switch to that tab and fix Skills or Rules on the spot. This is a personal preference — Skill Creator's auto-generation may suit others. In my case, manual refinement based on real development experience worked better.
4.3 Cross-Platform Support
everything-claude-code supports Windows/macOS/Linux, but my customized version is macOS only. Given the nature of a dotfiles repository, specializing for a personal environment is fine.
5. Features Added Independently
| Feature | Overview |
|---|---|
| Jujutsu (jj) VCS support | jj-workflow Skill, jj-describe / jj-git-push Commands |
| database-reviewer Agent | Specialized for MySQL/Aurora (query optimization, index design, schema review) |
| EARS format | planner Agent defines acceptance criteria in EARS → tdd-guide Agent converts to Gherkin |
| Vue 3 patterns | Vue 3 Composition API (Composables, Provide/Inject, etc.) added alongside React |
6. Conclusion
everything-claude-code is an excellent starting point. The four-layer design (Rules → Skills → Agents → Commands) was extremely helpful as a reference.
However, rather than copying it wholesale, it's important to reflect your own technical philosophy. I embedded these four non-negotiable convictions into my Rules/Skills:
- API idempotency: Understand the true nature of PUT vs POST
- Database consistency: Don't resort to caching, leverage transactions
- Structured logging: Machine-parseable logs for operational efficiency
- Makefile: The ultimate handover document
The discovery that Agents don't auto-inherit Skills also had a major impact on the design. Without this knowledge, I would have mass-produced Agents that didn't work as expected.
Claude Code configuration is not just tool setup — it's the work of codifying our technical philosophy into explicit knowledge. I recommend building on everything-claude-code while reflecting your own convictions in your configuration.
Appendix A: Agent Skills Inheritance
Explicitly specify skills using the skills: field in the Agent's frontmatter.
# agents/tdd-guide.md --- name: tdd-guide skills: - testing-principles - cucumber-playwright - typescript-testing ---
Shared content placement strategy:
- Example: Testing principles (TDD, Test Pyramid) → Created as
testing-principlesSkill - Main session: Auto-loaded when working on test code
- Agent: Explicitly loaded via
skills: [testing-principles]
Appendix B: Skill Content Guidelines
**DO include:** - Policies and directions (what to do) - Information requiring context7 or web search - Project-specific conventions **DO NOT include:** - General knowledge Claude already knows - Standard library commands - Basic language syntax
context7 integration rules:
Use context7 to verify documentation when: - Writing code with library-specific APIs that may have changed - Uncertain about correct usage patterns Do NOT use for: - Well-established, stable APIs (basic JavaScript, SQL) - Simple operations Claude confidently knows
Appendix C: TypeScript Skill Separation
typescript-patterns (generic: naming, async/await, type safety) ├── cdk-patterns (AWS CDK) ├── js-library-distribution (npm library distribution) ├── react-patterns (React/Next.js) └── vue-patterns (Vue 3 Composition API)
| Project Type | Skills Loaded |
|---|---|
| React app | react-patterns + typescript-patterns |
| Vue app | vue-patterns + typescript-patterns |
| CDK infrastructure | cdk-patterns + typescript-patterns |
| npm library | js-library-distribution + typescript-patterns |
| Pure Node.js | typescript-patterns only |
Appendix D: API Idempotency
| Method | Idempotent | Use Case | |--------|------------|----------| | GET | Yes | Retrieve resource(s) | | PUT | Yes | Create or replace at specific URI | | PATCH | No* | Partial update | | DELETE | Yes | Remove resource | | POST | No | Non-idempotent operations |
Common misconception: - "POST = create, PUT = update" → Wrong - PUT is idempotent (running twice produces the same result), POST is not (running twice creates two resources)
# PUT: Idempotent - client specifies the ID PUT /users/123 # Creates user 123 if not exists, replaces if exists # Running twice = same result # POST: Non-idempotent - server assigns the ID POST /users # Creates new user with server-generated ID # Running twice = two users created
Appendix E: Database Design
Principle: RDBMS Must Work Without Cache
**Caching is Often a Bad Habit:** - Caching hides poor query design and missing indexes - Caching breaks data consistency (stale data, race conditions) - Caching adds complexity (invalidation is hard) - Caching delays proper MySQL tuning **Before Adding Cache, Ask:** 1. Have you analyzed slow queries with EXPLAIN? 2. Have you added proper indexes? 3. Have you optimized schema design? 4. Have you tuned MySQL/Aurora parameters?
NoSQL usage guidelines:
| Use Case | Acceptable |
|---|---|
| Read-only master data | Yes |
| Logs that don't require transactions | Yes |
| Frequently updated data | No |
| Data requiring consistency with RDBMS | No |
Eventual consistency is harder than it looks. RDBMS transactions should be preferred.
Appendix F: Makefile
.PHONY: setup update help
setup: brew ansible playbook fish
@echo "Setup complete!"
update: playbook
@echo "Environment updated!"
help:
@echo "Available targets:"
@echo " make setup - Full initial setup"
@echo " make update - Run ansible playbook"
make setupsets up a new machine in one commandmake helpserves as documentation- Anti-pattern: Running raw commands like
npm run build,go test ./...directly
Enable the Hardware Acceleration of Chrome Browser on AWS Batch
In today’s rapidly evolving tech landscape, optimizing performance is a critical factor, especially when dealing with large-scale processing on cloud platforms. Many of you might find yourselves needing to automate Chrome on a server for various reasons. Additionally, you might want to navigate OpenGL-intensive websites using GPU acceleration. I was one of those people. However, if your tech stack isn’t perfectly aligned, this can be a daunting task.
In my quest to solve this issue, I scoured various QA sites, but I noticed that many users facing similar problems never received a conclusive answer. Therefore, I’ve written this article to address the gap and provide a comprehensive guide to enable hardware acceleration for Chrome on AWS Batch.
Steps to Enable Hardware Acceleration
Create a Docker Image with Chrome and Nvidia Support
First, you’ll need a Docker image that includes Google Chrome and the necessary Nvidia drivers. Here is a basic Dockerfile to get you started:
FROM --platform=linux/amd64 nvidia/cuda:12.5.0-devel-ubuntu22.04 WORKDIR /app ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Asia/Tokyo # For timezone RUN apt-get update && \ apt-get install -y software-properties-common tzdata && \ ln -fs /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ dpkg-reconfigure --frontend noninteractive tzdata && \ apt-get clean # ldd chrome | grep found # libnss3.so => not found # libnssutil3.so => not found # libsmime3.so => not found # libnspr4.so => not found # libatk-1.0.so.0 => not found # libatk-bridge-2.0.so.0 => not found # libcups.so.2 => not found # libdrm.so.2 => not found # libxcb.so.1 => not found # libxkbcommon.so.0 => not found # libatspi.so.0 => not found # libX11.so.6 => not found # libXcomposite.so.1 => not found # libXdamage.so.1 => not found # libXext.so.6 => not found # libXfixes.so.3 => not found # libXrandr.so.2 => not found # libgbm.so.1 => not found # libpango-1.0.so.0 => not found # libcairo.so.2 => not found # libasound.so.2 => not found RUN apt-get update && apt-get install -y \ libnss3 \ libnss3-tools \ libnspr4 \ libatk1.0-0 \ libatk-bridge2.0-0 \ libcups2 \ libdrm2 \ libxcb1 \ libxkbcommon0 \ libatspi2.0-0 \ libx11-6 \ libxcomposite1 \ libxdamage1 \ libxext6 \ libxfixes3 \ libxrandr2 \ libgbm1 \ libpango-1.0-0 \ libcairo2 \ libasound2 && \ apt-get clean # [ERROR:egl_util.cc(44)] : Failed to load GLES library: libGLESv2.so.2: libGLESv2.so.2: cannot open shared object file: No such file or directory # [ERROR:egl_util.cc(52)] : Failed to load EGL library: libEGL.so.1: libEGL.so.1: cannot open shared object file: No such file or directory RUN apt-get update && apt-get install -y libgles2-mesa libegl1-mesa && apt-get clean # [ERROR:gl_display.cc(520)] : EGL Driver message (Critical) eglInitialize: xcb_connect failed RUN apt-get update && apt-get install -y xvfb && apt-get clean # xvfb-run --server-args="-screen 0 1920x1080x24 +extension GLX +render -noreset" \ # chrome \ # --enable-logging --v=1 # --headless \ # --ignore-gpu-blocklist \ # --enable-gpu-rasterization \ # --enable-zero-copy \ # --use-angle=default \ # --no-sandbox RUN apt-get update && apt-get install -y \ libva2 \ libva-x11-2 \ libva-drm2 && \ apt-get clean
To get started, you’ll need a Docker image that includes the necessary Nvidia drivers. This Dockerfile will ensure Chrome runs smoothly. In my setup, I used Python’s Pyppeteer, which downloads Chrome, so there’s no need to install Chrome via apt-get. Of course, Puppeteer also works, and if you prefer, you can directly install Chrome using apt-get.
Pay close attention to the comments within the Dockerfile. The comments explain the commands executed, the errors encountered, and the libraries installed to address those errors. As of July 2024, this Dockerfile is functional. However, if you encounter any errors in the future, refer to these comments to guide your troubleshooting and adjustments.
Prepare Your Project
In this step, we will show an example using Pyppeteer in Python. If you prefer using Puppeteer, feel free to substitute Python with Node.js as appropriate.
There are a few key points to keep in mind, but one of the most important is to run your Python or Node.js through xvfb-run. This is crucial not only to allow Chrome to operate in a headless mode but also to enable GPU usage.
Here is an overview of what you need to do:
1. Prepare a shell script for running Python or Node.js on X
xvfb-run --server-args="-screen 0 1920x1080x24 +extension GLX +render -noreset" \ python3.12 /app/run.py "$@"
2. Run Chrome in a Python Script
import asyncio import logging from typing import TypeAlias from pyppeteer.launcher import launch _BrowserLaunchOptions: TypeAlias = dict[str, list[str] | bool] def _get_launch_options() -> _BrowserLaunchOptions: args = [ "--lang=ja-JP", "--no-sandbox", "--ignore-gpu-blocklist", "--enable-gpu-rasterization", "--enable-zero-copy", "--disable-gpu-process-crash-limit", "--use-angle=default", ] if logger.level == logging.DEBUG: args.extend(["--enable-logging", "--v=1"]) launch_options: _BrowserLaunchOptions = {"args": args, "ignoreHTTPSErrors": True} if logger.level == logging.DEBUG: launch_options["dumpio"] = True logger.debug(f"launch_options={launch_options}") return launch_options async def main() -> None: launch_options = _get_launch_options() browser = await launch(**launch_options) # do something you need await browser.close() if __name__ == "__main__": asyncio.get_event_loop().run_until_complete(main())
This is a code snippet. In this code, we only create the browser object, but you will need to further automate Chrome operations as per your requirements. The key point here is the launch options. If you get these options wrong, Chrome will not start. Pay particular attention to the arguments passed to args. In DEBUG mode, configure Chrome to output more logs. This way, if any issues arise, you can usually resolve them. If you cannot read the logs yourself, you can always rely on ChatGPT for assistance.
If you want to quickly verify that everything is working correctly, you can navigate to chrome://gpu, capture a screenshot of the page, and upload the screenshot file to S3. This will help you confirm that GPU acceleration is enabled.
page = await browser.newPage() await page.goto("chrome://gpu") await page.screenshot({"path": "./screenshot.png"})
As a side note, there is always a possibility of encountering errors in every operation, such as opening a tab, navigating to a URL, or retrieving content. Therefore, I write my code to restart from the point of opening a tab if any single operation fails. This process is repeated until it succeeds, but after five failures, it gives up. When automating Chrome, you need to write your code defensively to this extent.
3. Update the Dockerfile to adjust the Python Project
Please add the following content to the Dockerfile we prepared earlier. I will omit the details on how to create the requirements.txt.
# Install python3.12 RUN add-apt-repository ppa:deadsnakes/ppa -y && \ apt-get update && \ apt-get install -y python3.12 python3.12-distutils && \ apt-get install -y wget && \ apt-get clean # Install pip RUN wget https://bootstrap.pypa.io/get-pip.py && \ python3.12 ./get-pip.py COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . .
Set Up an Environment on AWS Batch for GPU-Accelerated Chrome
In this final step, we will set up an environment on AWS Batch that can utilize GPU-accelerated Chrome. For this example, we will use the g4dn instance type, which is optimized for GPU workloads.
Here is a snippet of the AWS CDK code to set up the necessary infrastructure:
export class BatchChromeStack extends cdk.Stack { constructor(scope: Construct, id: string, stage: string, props?: cdk.StackProps) { super(scope, id, props); const vpc: ec2.IVpc = this.getVpc(); const subnets = this.getSubnets(vpc); const securityGroup = this.getSecurityGroup(vpc); const instanceRole = this.createInstanceRoleAndProfile(); const { repository, image_name } = this.createAndDeployDockerImage(); const jobRole = this.createJobRole(); this.addSSMPolicyToJobRole(jobRole, stage); const bucket = this.createS3Bucket(); this.addS3PutObjectPolicyToRole(jobRole, bucket); const container = this.createContainer(image_name, jobRole, bucket, stage); repository.grantPull(container.executionRole); this.createEcsJobDefinition(container); const computeEnvironment = this.createComputeEnvironment(vpc, [securityGroup], subnets, instanceRole); this.createJobQueue(computeEnvironment); } // Omit many codes private createContainer(image_name: string, jobRole: iam.Role, bucket: s3.Bucket, stage: string): batch.EcsEc2ContainerDefinition { const logLevel = stage === 'production' ? 'INFO' : 'DEBUG'; return new batch.EcsEc2ContainerDefinition(this, `${this.NAME_PREFIX}ContainerDefinition`, { image: ecs.ContainerImage.fromRegistry(image_name), // g4dn.xlarge gpu: 1, cpu: 4, memory: cdk.Size.gibibytes(15), // 16GB - 1GB for OS jobRole: jobRole, logging: new ecs.AwsLogDriver({ streamPrefix: this.KEBAB_NAME_PREFIX }), environment: { BUCKET_NAME: bucket.bucketName, LOG_LEVEL: logLevel, }, }); } }
I have omitted quite a lot of details in this step. I did not include what you can search online or ask ChatGPT to get answers, as those are readily accessible resources.
The biggest issue I faced was that when I specified the memory size of 16GB, which is available on the g4dn.xlarge instance, in the EcsEc2ContainerDefinition, the instance failed to launch. However, it did launch with 15GB. I believe this is a quirk of AWS Batch.
If you need the full version of the CDK code or if something is not working correctly, feel free to reach out. If I feel inclined, I might provide more detailed information.
舌癌になったので、頭の中を書き出してみた
なぜ、この記事を書くのか?
約9年ぶりの投稿です。9年前、情報公開が難しい会社(とあるFinTech企業)から情報公開を価値と認めてくれる会社(gumi)へ転職したため、所属企業の名前で記事を書いたり、イベントに登壇したりしていました。結果、この個人ブログに書くネタがなくなり放置していました。そして二年前、WOVN という会社に転職し、Developer から Product Owner (CSM-SM 持ってるのに Scrum Master じゃないのかというツッコミ歓迎) に役割を変え、さらに書くネタがなくなりました。
ところが、2022年9月に舌癌が発覚し、大きく私の死生観が変わったため、個人ブログにまとめてみようかと思います。私自身が私以外のがんサバイバーの方々の明るい日記に心を救われため、この記事も、少しでも、同じ境遇の誰かの励みや助けになれば幸いに思います。
伝えたいことのまとめ
ほとんどの方に言えること
- 40過ぎたら、がん検診を絶対受けて!
- 日本の大学病院の標準治療を信じよう!
- 癌と共に歩もう!
- 運動、睡眠、食事、笑顔、コミュニケーション力と真剣に向き合おう!
人によって違うこと
- 人によるけど、舌の生検、そんなに痛くないよ
- 人によるけど、全身麻酔、怖くなかったよ
- 人によるけど、舌の部分切除の術後は、痛み止め不要だったよ
娘にドヤったこと
- 自分が死ぬことを真に自覚するまで、人は何歳になっても子供なのだよ( ー`дー´)
経緯
2022年6月
何となく10年前に虫歯を治療済みの歯がしみるような気がする。(奥から二番目の奥歯)
しかも、同じ側の耳の奥も痛いし、頭痛もする。
2022年8月
歯の症状は治っていたが、耳の奥が痛いため、耳鼻科と歯医者さんの選択に迷い、とりあえず虫歯だったら嫌だなーと思い歯医者さんへ。しかし、該当の部位に虫歯は見つからず。歯石掃除、歯磨き指導、ベロ磨き指導を受ける。帰宅後、ベロ磨き中、舌の側面に 2mm くらいの白い口内炎のような出来物を見つける。(9月に白板症と分かる) とりあえず、ベロ磨きで擦っても痛くないため放置する。
2022年9月
耳の奥の痛み、頭痛が気になり、耳鼻科へ行こうかと思ったが、妻の勧めで自宅の近所のかかりつけの内科へ。そこの先生は、過去、他の病院でも分からなかった私の病気(既に快癒してる)を見抜いて治療してくれた実績があり、何人かのお医者さんを見てきた看護師の妻から見ても名医とのこと。
そして、かかりつけ医に診てもらったところ、これは舌癌の可能性があるから、大学病院への紹介状書くねとなった。虫歯くらいの気持ちでいたところに生死に関わる「癌」と聞いてしまい、ショックを受けた私は混乱しながら、とりあえず、仕事の予定を見ながら一週間後に大学病院の検査の予定を入れてもらった。
後に妻から聞いた話によると、先生的には、堀ちえみさんの件があったから、疑わしきは、早めに検査するべきだと思っただけで、癌確定とは思っていなかったらしい。とはいえ、ショックを受けた私は翌日から夜に寝れなくなり、昼は微熱と悪寒に悩まされ、耳痛も頭痛も酷くなった。そして、2日後、再び妻に連れられて、かかりつけ医のところへ行き、検査予約を一週間後ではなく、数日後の予定に早めてもらい、睡眠導入剤を処方してもらった。また、念のため血液検査をしてもらった。結論、悪寒や頭痛は心気症だった。(これは後に調べたことだか、癌は末期まで痛みがない)
その後、恐る恐る大学病院へ行き、細胞診というブラシで病変を擦って調べる検査を受けた。結果が出るまで生殺し状態で、不眠は続いた。この頃、死に備えて何をすべきかと考えていた。
ちなみに担当医の初見では、この小ささだと、耳や頭の痛みは全く関係ないと思われるとのこと。これは、あとから気がついたことだけど、人は何でも癌や標準治療の副作用のせいにしてしまうが、それに本人が気がつくのは本当に難しい。私は癌自身は痛みを伴わないと知ってから腹落ちした。
2022年10月
大学病院で細胞診の結果を聞いた。主治医が「結果は3です。」と伝えてきたため、あ、ステージ3なのか、人生が終わったなーと考え「そうですか…」と答えたら主治医から「いや、クラス3で安心しないでください」と注意で返された。ん?何か話が噛み合ってない。安心したんじゃなくて、運命を受け入れたんだよ?あれ…?よくよく話を聞くと、検査結果は五段階のクラスで表現されるらしく、大雑把に言うとクラス1-2は良性、3は不明、4-5悪性。だから、もっと詳しく調べるために、次は生検しましょうとのこと。患部を部分麻酔して切り取って病理検査し、より詳しく判断するのだとか。また、不調の理由が不明な期間が続くのかと不安になる。
ちょっと舌癌の生検についてネットで検索すると、痛みが強いとか、夜寝れないとか、一週間は痛いとか、散々な情報しか見つからず凹む。主治医からは、人によって異なるが、大凡、大した事ないと感じる人が多いと伝えられる。
そして、10月末に生検を受ける。麻酔の針は4本刺されたが、まー、歯医者で慣れてるから、それほど痛く感じない。その後は痛みを何も感じなかった。切っている最中は電動メスで止血していたらしい。最後に四針縫って生検終了。出血確認後に解散。妻の勧めで、すぐに薬局でロキソニンをもらって飲んだ。当日、麻酔が切れてから疼くような痛みを感じたが、食事以外で強い痛みを感じることはなく、翌日から痛み止めを飲むのは止めた。食事中、ちょっと気を抜くと、余った糸を噛んで悲鳴を上げていたが、三日目からラーメンを食べられるくらいに回復していた。生検の結果が出るまで、最大で二週間かかるらしく、またもや、モヤモヤ期間が続くことに凹む。とはいえ、生検のあと、耳と頭の痛みが消えた。近所のかかりつけ医の話によると、舌の神経は、いろんなところに繋がっているからねーとのこと。
2022年11月
11/7 に生検の結果、T1M0N0 の癌(高度異形成)と結果を聞く。垂直方向は生検で取り切ったが水平方向には残っているとのこと。放置した場合、広がる可能性ある。このサイズだと、抗がん剤も放射線もデメリットが大きいため、すぐに手術で切除が良いとのこと。安全マージンをとって大きく切除するが、味覚も会話も術後と変わらないと説明を受け、切除で決心する。手術中、迅速病理診断を行い、もし、癌の取り残しがあれば、追加で切除するという話もあり、とても怯えた。また、術中に神経を触るか切断すると、舌先に痺れが長期間出るとのこと。怖すぎる。一番早い手術の予約でも 12/2 とのことで、三週間待ち。遅い…と思いつつ、その日で予約したのたが、実は、この三週間が、後から振り返ると、とても良い準備期間となった。
私の仕事は人と話すことだし、趣味は料理なので、言葉と味覚が温存されるだけ、ありがたく思おう…。
この癌のサイズだと、基本的には大丈夫だけど、念のため、鎖骨から上の CT も撮りましょうとなり、そちらも翌週に予約。CT 自体は、造影剤を点滴でいれる必要があり、しかも、ちょっと太い針を刺すが、そんなに負担ではなかった。撮影中、ずっと痛かったけどね…。そして、結果、リンパへの転移が疑われる微妙な結果が出てしまう。放射線技師が、これは怪しいと言っており、主治医は、こんな小さいの関係ないけど…うーん、経過観察しましょうとのこと。これが転移だとステージ3になるし、リンパ切除の追加手術になるとのこと。癌がリンパに転移すると、大雑把に言うと免疫力が落ちるため、非常にまずい…。しかし、顎や首のリンパを切除すると後遺症の克服が大変そう。うむむ。
2022年11月 (準備期間)
癌と確定したので、癌とは何かここで真剣に調べた。その結果、私の死生観も大きく変化した。私はいつも何か調べる際、速効性のある簡単な行動を示しているものは無視する。(私が作る文章やプレゼン資料は、その系統なのにw) 重要なのはマインドセットとエビデンスレベル。結果、次の考えに至る。
- 癌は寛解するが完治は難しい
- 癌と共に生きる(本来の寿命に近づける)
- 癌は末期まで痛みを伴わない(だから初期で見つけるのは難しい)
- 痛みを伴うのは癌の治療行為
- 治療行為に耐えられる身体と心を作る
- 癌と身体の不健康は直結していない (癌でも健康はあり得る)
- 心まで病にする必要はない
- 日本の大学病院の癌医療は世界的にみて高い水準
- 標準治療はすごい
- 標準治療の「補助」として、他の医療行為はある (標準治療の副作用を軽減したり効果を後押しする)
- 他の医療行為は詐欺が多すぎる (見抜き方はあるが…絶対ではないから書かない)
- 免疫力を測る方法はない(その提案は多くある)
- とはいえ、40歳から免疫力は格段に落ちる
- 情報、睡眠、運動、食事、笑顔、人とのコミュニケーションを「真剣」に大切にする
ちなみに舌癌については次の通り。
- 昔は、刺激物(酒、タバコ、辛いもの)の摂取が好きな人たちに多かった
- 今は、顎の狭い人たちに多い(歯が舌に当たり続けるため)
- 30代なら歯を矯正する
- 40代なら歯を少し削って丸めるか、マウスピースを付ける
私は45歳なので、大学病院の主治医の先生からの提案でプラスチックのマウスピースにした。これは術後の舌を切除した痛みも軽減することに術後に気がついた。私は、もともと歯を食いしばる癖があり、舌も頬も噛み跡だらけだったので、もうマウスピースから離れられないくらい依存している。
それから、とりあえず、約二週間半ほど使って身体を準備することにした。というか、そのくらいの悪足掻きしか出来なかったとも言える。ここで行ったことに意味があったのかは、全く分からないが、心の安定には繋がったし、体脂肪計の測定結果が劇的に変わった。
- 毎朝起きたら水だけ飲んで、10分間のインターバルトレーニング (アクトレブログ参照のこと)
- 日に高負荷の自重スクワット3セット (1セットで歩くのが困難になるため、間隔は開けてる)
- 野菜中心の食事と毎日45g の納豆を食べる (筋肉量のために肉も米も食べる)
- 寝るために、18:00食事、20:00風呂(40度でBARTHに20分)、22:00柔軟(オガトレ参照のこと)
- 妻と過ごす (家でドラマみたり、映画館行ったり、外食したり、手を繋いで寝てもらったりw)
BARTH 高いよね…。でも睡眠のために課金した。
2022年12月
12/1 入院し、12/2 全身麻酔にて切除。そして、この記事を書いているのが 12/3 (今日)。特に 12/3 はブログを 9 年振りに更新しようと思い立つくらい暇だった。
12/1 妻に付き添われて入院手続きを行う。病棟のベットに案内されたあと、荷物を置いて妻と共に案内のコンビニへ買い出しへ。病院に持ち込んだのは、下着、スマフォ、スマフォ充電用のケーブル、マスクのみで、他の必要なものは、レンタルと現地調達が可能。しかも、コンビニは電子マネー、レンタルは退院時の後払いが可能なので、スマフォがあれば財布も不要。
コンビニで購入したものは次の通り。
- 手術時に着用するT字体(ふんどし)
- 食器用洗剤とスポンジ
- いろはす
レンタル手続きしたものは次の通り。
- パジャマ
- バスタオルとフェイスタオル
- 歯ブラシ、歯磨き粉、コップ、シャンプー、リンス、ボディーソープ (レンタル屋だけど買い切り)
その後、妻と院内のカフェでコーヒーを飲んで、雑談して解散。コロナ禍で一度病棟に戻ると面会できないため、術前は会いに来なくて良いと伝える。ただ、術後すぐには、会いたいねーとだけ伝えて解散。その日のお昼からは暇かと思っていたら、麻酔科医、歯科医、口腔外科医の問診や、手術前の歯石取りなどがあり、そんなに暇ではなかった。お昼と夜は、病棟のご飯を食べたが、とても美味かった。生検の傷が癒えてから、食べるもの全てが美味く感じるから、そのせいだと思う。お昼ご飯の後には、気持ちを落ち着かせるためにスクワットをしまくった。もはや、スクワットは精神安定剤。
夜、シャワーを浴び、指示通りに足の裏に油性ペンで名前(漢字フルネーム)を書き入れ、ベットに入る。しかし、ベットが固く背中や腰が痛くなり、また、翌日の手術の迅速病理診断の結果や、術後の痛みが怖くなってしまい、結局、1時間置きに目が覚めてしまった。
12/2 朝一の手術で、かつ、術後はしばらくシャワーを浴びれないとの話だったので、7:00 に病室に備え付けのシャワーを浴びて落ち着きを取り戻す。8:00 にふんどしを締め、オペ着を見にまとい、昔、開発に携わったソシャゲのデイリーミッションを消化し、ギルメンに挨拶してスマフォを鍵付きの箱に入れて、お迎えを待った。その後、お迎えの看護師さんが来たので、いざオペ室へ。オペ室へ移動していると、オペ予定の患者の方がどんどん合流してきて、こんなに大勢が朝から手術を受けるのか…と圧倒される。
その後、名前を呼ばれ、何点か確認してオペ室へ移動。移動中、様々な機器が大量に置かれているのが興味深く、写真を撮りたいなーとキョロキョロ見回していたらすぐにオペ室に到着。執刀の主治医が見当たらず、心細くなるが、麻酔科医と挨拶して指示に従う。点滴の針を入れますよーと言われたあと、何度もブスブス刺され、痛いっすと言ったら、別の麻酔科医が針を入れてくれた。ちょっと、こんなんで大丈夫?と思っていたら、酸素マスクをつけられ、「まずは酸素ですよー」と言われた後の記憶がない…。
気がついた時、主治医の先生が私の乗ったベットを押しながら「もう終わりましたよー。10:30 ですよー。」と話しかけてきて覚醒した。先生の顔を見れて安心しましたーと答えた記憶がうっすらあるw
そこから待機室で30分待つことに。吐き気があれば教えて欲しいとのことで、吐きそうと伝えたが、大きなゲップが出ただけでスッキリしてしまった。とは言え、吐き気止めの薬を点滴に入れてもらう。
30分後、病棟の看護師に身柄を引き継がれ、病室へ移動。移動中、病棟の看護師さんに、背が高いですねーとか雑談を振られたので、頑張って受け答えしてみたが、記憶が曖昧で何と答えたか覚えていない。途中、看護士さんが、実は奥さんが来ているので、病棟の入り口で少しだけ会えますと教えてくれた。妻には術後に会って無事を直接伝えたかったので、会えて本当に良かった。しかし、私は妻に何を伝えたのか、意識朦朧としていて、あまり記憶に残っていない。とは言え妻が曰く「舌の手術したはずなのに、はっきり話してたよ」とのこと。
その後、三時間、枕無しで酸素吸入の儀がスタート。寝てやり過ごそうと思ったが寝れず、スマフォを触って何とかやり過ごす。酸素マスクが外れた後、ほぼ半裸の貧ぼっちゃまスタイルからパジャマに着替え、点滴から抗生物質を入れてもらいつつ安静にすることに。とりあえずスマフォで方々へ「手術終わって覚醒したよー」の連絡を入れまくる。
しばらくすると、主治医の先生が挨拶に来てくれて、一回の切除で終わり、迅速病理診断は上下左右奥の5方向に問題なく、妻にそれらを説明したことなど教えてもらった。また、後で回診で大勢で来るけど、寝てて良いからねーとのこと。そして、今日から夕ご飯食べて良いから、病棟に伝えておくねーとのこと。え…食べれるの、怖すぎる…と思ったが、早く退院したいから挑戦することに。結果、完食できた。痛み止めの投与がされていないのに痛くないぞ…。
その夜、病院のベットが硬い理由を調べ、角度を変えるなどの工夫で、腰や背中の痛みが軽減されることを知る。私的には寝る時に14度、起きてる時は46度が良かった。また、点滴をしているとトイレが近くなるため頻繁にトイレに行くのだが、その度に血が逆流する。これも、心臓より針の刺さってる箇所を低くすると解消しやすいことをソシャゲ経由でギルメンに教えてもらい解決。
12/3 硬いベットと点滴のせいで、あまりよく寝れず。かつ、6:00 からしゃっくりが止まらなくなる。ご飯を食べて胃が温まるとしゃっくりは止まり、冷たいものを飲むとしゃっくりが始まることに気がつく。軽く調べてみると全身麻酔の一時的な後遺症らしい。とりあえず、8:00頃に看護師さんに、お風呂に入って着替えたい旨を伝えると、実は外来から呼ばれているので、先にそっちに行ってーとのこと。仕方ないので点滴を引きずって外来へ行くと、途中で主治医の先生と合流。ちょっと移動を手伝ってもらいつつ受付で待っててねーと分かれる。その後、診察室で診察を受け、この治り具合なら 12/5 に退院して良く、点滴もすぐに外すことに。都合悪ければ、もっと入院できるけど…となり、いえいえ、絶対帰ります!と答えた。その後、病室で看護師に点滴をとってもらい、念願のシャワーとお着替え。麻酔科医に痛み止め一回も処方されませんでしたね…と言われ、あんなに痛みを恐れていたのは何だったのかと、自分自身に呆れる。多分、主治医の腕が良いからかもしれないし、下準備で筋トレしておいたのが効いたのかもしれない。お昼ご飯を食べてしゃっくりが止まったので、スクワットをして一休みしてから、院内の庭園に遊びに行き、外の冷たい空気を吸ったらしゃっくり再発。コンビニに寄ってお茶を購入し、電子レンジで温めて暖を取ることに。
続きに関して
時間軸が今に追いついたので、一旦、ここで筆を置きます。これから、退院した後も転移に備えて二週間に一回ペースでリンパ節の様子を見て行く必要がありますし、切った部位の病理検査の結果を確認する必要もあります。最低五年は病院へ通うことになるから、気が向いたら、続きを書こうと思います。
最後に
家族や妻の親族、友人、同僚に心配をかけて本当に申し訳ないと思いつつも、様々な方法でサポートをいただき本当に感謝しています。必ず受けた恩は返します。特に妻には、本当に感謝しており、もう何を返して良いのか想像もつかないけど、一生をかけて何か幸せ的なものを返して行きます。
RabbitMQ 3.x から Queue のミラーリング方法が変更になった
今まで, Queue 作成時に指定していたミラーリングのパラメータは廃止になり, rabbitmqctl コマンドで指定するように変更なった.
Perl の AnyEvent::RabbitMQ や Python の kombu(celery) で x-ha-policy を指定する方法は, RabbitMQ 2.x までしか通用しない.*1
経緯や詳細は, 下記二つを参照の事.
- RabbitMQ >> Blog Archive >> Breaking things with RabbitMQ 3.0 - Messaging that just works
- RabbitMQ - Highly Available Queues
指定方法
Web UI の Manage Console からも指定できるが, 今回は rabbitmqctl の例を挙げる.*2
Usage は下記の通り.
$ rabbitmqctl set_policy <ポリシーの名前> <パターン> <モード> [<優先度>]
| ポリシー名 | ポリシーを一意にし, 更新や削除の操作対象とする. |
|---|---|
| パターン | キュー名がパターンにマッチした場合, ポリシーの対象とする. 正規表現が使える. |
| モード | RabbitMQ - Highly Available Queues 参照の事. |
| 優先度 | 数値が高い程, 優先. 未指定で 0 が入る. |
指定例
全てのキューをミラーリングする(ものぐさ設定w;).
$ rabbitmqctl set_policy all '^.*' '{"ha-mode": "all"}'キュー名の接頭辞に ha が付いた場合にミラーリングする.
$ rabbitmqctl set_policy ha-all "^ha\." '{"ha-mode":"all"}'キュー名の接頭辞に amq が付いた場合(キュー名を指定せず, RabbitMQ に自動採番させた場合) "以外" にミラーリングする.
$ rabbitmqctl set_policy ha-ignore-amq '^(?!amq\.).*' '{"ha-mode": "all"}'運用中にポリシーの変更が可能らしいが, 検証はこれから行う予定.
運用中にポリシーの変更は可能. また, クラスタリング時の Manage Console のポリシー表記が変だったので, 下記のコマンドで動作確認した方が良い.
$ rabbitmqctl list_queues name policy pid owner_pid slave_pids messages_ready messages_unacknowledged messages
尚, ポリシーは, パターンにマッチする Exchange にも適用されている. これが, どのような影響を及ぼすのかは調査中.
Python の amqplib とか py-amqp で Message を Consume する際, ヘッダに x-death が付与されていると落ちる件
データに謎の 'A' という型が定義されているのが問題. AMQP の Elementary domains を見たのだけれど 'A' が何か見当たらない…。助けて偉い人orz
とりあえず, amqplib 1.0.2 は, 以下の黒魔術で回避可能. kombu 2.5.0 から amqplib に代わり py-amqp がデフォルトで使用されるのだけれど, そちらはおいおい.
from struct import unpack from decimal import Decimal from amqplib.client_0_8.serialization import AMQPReader def _patched_read_table(self): """ Read an AMQP table, and return as a Python dictionary. """ self.bitcount = self.bits = 0 tlen = unpack('>I', self.input.read(4))[0] table_data = AMQPReader(self.input.read(tlen)) result = {} while table_data.input.tell() < tlen: name = table_data.read_shortstr() ftype = ord(table_data.input.read(1)) if ftype == 65: # 'A' これが新しく加わった!! len = unpack('>I', table_data.input.read(4))[0] ftype = ord(table_data.input.read(1)) if ftype == 83: # 'S' val = table_data.read_longstr() elif ftype == 73: # 'I' val = unpack('>i', table_data.input.read(4))[0] elif ftype == 68: # 'D' d = table_data.read_octet() n = unpack('>i', table_data.input.read(4))[0] val = Decimal(n) / Decimal(10 ** d) elif ftype == 84: # 'T' val = table_data.read_timestamp() elif ftype == 70: # 'F' val = table_data.read_table() # recurse else: raise ValueError('Unknown table item type: %s' % repr(ftype)) result[name] = val return result AMQPReader.read_table = _patched_read_table
Python Web Framework Advent Calendar 2012 (9日目) Django Model で Named Scope
前置き
この記事は、2012 Pythonアドベントカレンダー(Webフレームワーク) - connpass の 9 日目の記事となります。
今回は、Rails の Named Scope の真似を Django Model で実現する方法と、それを利用した論理削除の紹介を行います。
Django Model で Named Scope を実現する
そもそも何をしたいのか?
まず、ECサイトやソシャゲー等のユーザ情報から、最近登録したユーザの中から直近のアクセス順に上位5人を取得する例を挙げます。
import datetime from django.utils.timezone import get_default_timezone # 一週間以内の登録を "最近登録した" とみなす dt = datetime.datetime.now() - datetime.timedelta(weeks=1) # utc でも良いけれど、何となくローカライズ dt = get_default_timezone().localize(dt) User.objects.filter(created_at__gt=dt).order_by('-logged_in_at')[:5]
Named Scope を使用すると、次のようになります。
User.objects.by_newbie().order_by_active()[:5]
Named Scope を作る
では、実際の実現方法を紹介します。
import datetime from django.utils.timezone import get_default_timezone from django.db import models from django.db.models.query import QuerySet # Manager と QuerySet で同様のメソッドを使用するので Mix-in Class として切り出す class UserScopesMixin(object): _newbie_term = datetime.timedelta(weeks=1) def by_newbie(self): dt = datetime.datetime.now() - self._newbie_term dt = get_default_timezone().localize(dt) return self.filter(created_at__gt=dt) def order_by_active(self): return self.order_by('-logged_in_at') # QuerySet に Scope を Mix-in する # 継承順は賛否分かれる所ですが、この記事では、社内の目があるので Mix-in Class を後ろに羅列します(w; # 蛇足ですが、私は、私用で Python を書く場合に限り、Mix-in Class を前に羅列する派です class UserQuerySet(QuerySet, UserScopesMixin): pass # Manager に Scope を Mix-in し, 上記で定義した QuerySet を返すようにする class UserManager(models.Manager, UserScopesMixin): def get_query_set(self): return UserQuerySet(self.model) # 上記で定義した Manager を objects に設定する class User(models.Model): objects = UserManager() created_at = models.DateTimeField(auto_now_add=True, index=True) logged_in_at = models.DateTimeField(auto_now=True) @classmethod def get_active_newbies(cls, limit=5): return User.objects.by_newbie().order_by_active()[:limit]
結局、get_active_newbies() を定義するのであれば、Named Scope なんて不用ではないか?と思われるかもしれません。
しかし、get_active_newbies() の様なメソッドを多数定義する場合、スッキリ書けるのでオススメです。
また、Named Scope が癖になっていると、そもそも QuerySet をカスタム済みであるため、他のカスタム QuerySet を組み込む際に労力が減るという副作用もあります。*1
論理削除の実例
物理的にレコードを削除せずに、削除フラグを立てて削除した事にするアレ。
class LogicalDeleteScopesMixin(object): def by_alive(self): return self.filter(deleted_uuid='') def delete(self): self.update(deleted_uuid=uuid.uuid4(), deleted_at=datetime.datetime.now(pytz.utc)) class LogicalDeleteQuerySet(QuerySet, LogicalDeleteScopesMixin): pass class LogicalDeleteManager(models.Manager, LogicalDeleteScopesMixin): def get_query_set(self): return LogicalDeleteQuerySet(self.model).by_alive() # Mix-in Class であるため、object を継承したいが、 # Django Model の制約により models.Model を継承する必要がある。 class LogicalDeleteModelMixin(models.Model): class Meta: abstract = True class RedeletedError(Exception): pass objects = LogicalDeleteManager() # delete_at を有効/無効の確認に利用すると、 # 一意キー制約を設けた際に、一秒以内の delete が使えないため、 # 有効/無効を判断するための UUID フィールドを設ける。 # 初期値に NULL を指定すると、NULL はレコード毎に異なる値と認識されるため、 # UUID フィールドを一意キー制約に含められない。 # そこで、初期値には空文字列を明示的に指定しておく。 deleted_uuid = models.CharField(max_length=255, db_index=True, default='') # 念のため、記録として削除日時を残しておく。 deleted_at = models.DateTimeField(blank=True, null=True) def delete(self): if self.deleted_uuid: raise self.RedeletedError, self.pk self.deleted_uuid = uuid.uuid4() self.deleted_at = datetime.datetime.now(pytz.utc) self.save()
早速、先ほどの User Model で使用してみましょう。
# LogicalDeleteScopesMixin を継承する class UserScopesMixin(LogicalDeleteScopesMixin): pass # 内容に変更がないため省略 # LogicalDeleteScopesMixin を継承して UserScopesMixin を定義したので # UserQuerySet に変更はない。 class UserQuerySet(QuerySet, UserScopesMixin): pass # by_alive() を使用する必要がある class UserManager(models.Manager, UserScopesMixin): def get_query_set(self): return UserQuerySet(self.model).by_alive() class User(models.Model, LogicalDeleteModelMixin): pass # 内容に変更がないため省略
その他
私は、Python 歴 = Django 歴 = 半年未満であり、Django 以外の他の Python Web Framework の知識は皆無という状態ですが、今回紹介させて頂いた Named Scope や、Class Based View の存在から、Django は OO 設計し易いフレームワークだと認識しており、これからも末永くお付き合いできれば嬉しいなぁ〜と考えております。
参考 URL
ZeroMQ Erlang Binding(NIF) の inproc と Erlang の素のメッセージ送信の速度を比較してみた
コードと結果は下記の通り
https://gist.github.com/3193117
Erlang で作ったサーバに LL で作ったワーカーをぶら下げようと考えており、どうせならナウでヤングな ZeroMQ を間に入れてみようと思い立ちました。
ズボラな私は、ZeroMQ にワーカーのロードバランスをして欲しかったので、Erlang の中で Queue デバイスを使用し、そこに複数の Erlang プロセスから inproc でメッセージを送信しまくる予定でした。
しかし、ここまで素のメッセージ送信と速度に差があるなら、Erlang の中で自前でロードバランスした方が良さそうかなぁと…思い直してます。
ちなみに、inproc を使ってみて初めて気がついたのですが、inproc は他のトランスポートと下記の点で異なります。
- bind と connect に使うコンテキストは同じ物でなければいけない
- connect の前に必ず bind を行う必要がある