以前は、インストール時に Administrator のアカウントが作成されていて、それにプラスする形でローカルアカウントを作っていました。これは Linux での root アカウントと同じで、消すと OS ごと死んでしまいます。なので、root アカウントや Administrator アカウントは外部からログインできないようにする(リモートデスクトップや ssh など)のが定番なのですが、Windows 11 の場合はそのあたりが曖昧になってしまっています。
会社のドメインやポリシーを使っている場合は、管理者権限のアカウントと社員が使うアカウントを区別します。しかし、家庭で使っているようなアカウントの場合は、もう少し緩くてもいいでしょう。さらに言えば、会社のようなポリシーをきつくした環境を作ってしまうと、家庭の PC ではオーバースペックでややこしいことになります。
実際、私の環境では Windows 11 Pro に Microsoft ID で作った PC に対して、リモートログインができません。おそらくドメインサーバーを入れればいいんですが、それはオーバースペックですよね。そういう、もともとのローカルネットワークでの環境に Windows 11 の Microsoft ID アカウントの強要は適していないということです。 (実際の原因はわからないのですが、度々発生するので、リモートデスクトップ用のローカルアカウントを作成しています。多分、Wi-Fi 等のネットワーク関係だとは思うんですが、ちょっとわからなすぎです)
で、先の手順で作る訳ですが、実は 3 の部分を実際にやったことがないのです。消せるはずなのですが、先に書いた通り「インストール時に使ったアカウントを削除すると、えらいことになる」ことが多かったので、最新の Windows 11 ではよくわかりません。
Microsoft アカウントで作成
最初のアカウントは通常の Microsoft アカウントを使います。新規に作ってもいいのですが、実験用メールを使いまわすのは大変なので、業務用のアカウントを用意しておくとよいです。OneDrive の同期や位置情報などをは切っておきます。
スマホの Authenticator で認証を通します。
「新しい PC としてセットアップする」を忘れないように。
Microsoft アカウントでログインできた状態です。
さて、powershell と立ち上げると、ホームディレクトリが「c:\Users\masud」になっていて、激おこなんですよ。後から、ディレクトリを変更することも可能なのですが、やめておいた方がいいです。せめての Microsoft アカウントの @ の前を取ってくればいいのですが、これが暫く放置されています(次のアップデートで、フォルダーが指定できるようです)。
Linux で SQL Server が動くと言われた当初のころから、ちまちまと Linux に入れたみたことがあるのだけど、なかなかうまくいかない。当時は、Linux + dontet の環境が貧弱だったせいもあるし、SQL Server on Linux がまともに動いていなかったというのもある。じゃあ、今はどうなのか?というと、(かなりズルいが)Docker で構築するのがベストである。Docker 上ってのが Linux なのかが不明なんだけど(私としては、Docker 上ってのと Linux 上ってのを分けたい派なんだが、これは後述しよう)、ひとまず Docker ≒ Linux 上という意図?のもと、それだったら今ならなんとかなりますね、程度には何とかなる状態になっている。ちなみに、macOS 上はわからん。そもそも、macOS 上で開発環境ならばまだしも、実運用環境はあり得ませんよね(と暴言を吐いておく)。まあ、mac server を使うのもそれなんだけど、少なくとも現時点ではクラウド上と言えば Linux と一般的には決まっている(これも Azure 上では Windows Server が動いていることは伏せておく)。あくまで、一般的な SE やプログラマの範疇で、開発環境ないし運用環境を考えてみた結果、
開発環境の構築は、いわゆる LAMP 環境の方が便利ではあるが、SQL Server も Docker を利用して手軽に構築できるまではできている。
クラウド運用環境としては、Azure, AWS と分かれる。AWS 環境では SQL Sever は自前で構築しないといけないので面倒がだが、Azure 環境では SQL Server が用意されているので、これを使うことができる。なお、Azure では、SQL Server のほうが MySQL を立てるよりも安いので「安価」という点でも有利となる。AWS の場合は、当然のことながら、MySQL や PostgreSQL が選択肢となる。
のように、Linux + SQL server + dotnet の環境はお薦めしない。止む無く、既存の SQL Server のデータをそのまま持って行きたい場合に限るだろう。運用を考えれば、
Windows Server + SQL Server + dotnet
クラウド上の Azure SQL Server + Azure Functions でマイクロサービス
テスト用バックエンドとして Azure 上に SQL Server + dotnet 環境で web api サービスあるいは MCP サービス
に限るだろう。
Linux + SQL Server + dotnet 環境を Docker 内に構築する
忘れられているが、Windows Server の Docker コンテナ(ホストではなく)というのがある。忘れ去られているが。それを使ったほうが SQL Server は安定するのではないか、と思うのだが、GUI がない場合 SQL Server の設定は結構面倒なので、素直に Linux Docker を使ったほうが便利です。
既存の SQL Server のデータを移行しないといけない。カラム名が日本語の場合とか。これが一番多いと思われ。
って、ところですね。Docker で構築するのだったら、同じような手順で Linux + Laravel + MySQL という組み合わせも手軽にできるので、実は大差がありません。これも、自分にとって手慣れているか否かの違いです。開発環境として試験的に使いたいときは、MySQL や PostgresSQL よりも SQL Server + LINQ の組み合わせの方が早いです、という .NET 開発者向けです。
じゃあ、運用上どうなんだ?という話と、運用時に Docker 上でよいのか?という疑問があります。Docker イメージとしては microsoft 社が提供するる”mcr.microsoft.com/mssql/server:2022-latest” を使えば、インストールが簡単です。が、当然のことながらオンプレの PC などに直接入れる場合はここがハードルになります。ほかにも、10億件のレコードの場合 Oracle という選択肢があります。Oracle の場合も SQL Server と同じように Docker イメージが用意されています。
oracle/docker-images: Official source of container configurations, images, and examples for Oracle products and projects https://github.com/oracle/docker-images
あと、SQL Server はクライアントからの接続にパイプを使っているときが一番高速で TCP/IP 経由だとちょっと遅いんですよ。それに、SQL Server のファイルアクセスは特殊で、このあたりは Windows Server に最適化されているのですが、Linux 版の場合はどうしても posix 経由になってしまうのでパフォーマンスが落ちがちです。が、そこまで気にするのもどうかと思うし、そこまでチューニングしないといけない環境の場合は、Windows Server + SQL Server を選びますよね。なので、Linux + SQL Server の組み合わせははどうしても中途半端な気がするのです。 そうでもあっても、.NET (特に LINQ)が使いたい場合には、dotnet + SQL Server の組みわせがよいので、運用パフォーマンスよりも、開発パフォーマンス(不具合修正なども含めた保守・改修のパフォーマンス)を優先する場合には、Docker 上でもアリかなと思うのですが、果たしてどうでしょうか。
カテゴリー:開発|Linux + SQL Server + dotnet 環境を構築する(但し、Docker 上で) はコメントを受け付けていません
他にも四段階をステップとして、営業活動を合理的に示して、横展開できる状況を作っているのが K 社の営業方法である。なので、上記のステップを営業している個人のみが使っていても K 社には追い付けないし、合理化の恩恵が受けられない。これが、K 社の営業として同じ形で横展開される形で浸透しているからこそ、同じスタイルを貫けるし、それが客先に対しても同じ品質(営業としての)が得られるという安心感(継続であろうが新規であろうが)があると思われる。
さらに言うと、K社では昼休みがは短い。たまに、着替えは勤務時間に入るのか否か、という話が X に流れることがあるが、K 社では昼休みは、午後1時に着席していないといけない状態になる。昼に外出禁止のところもあるようだが、外出は自由である。しかし、時間内に戻ってこないといけないので本社ビルのエレベーターは激混みである。時間通りに戻ってきては間に合わないので、少し前に戻らないといけない。当然、出社もそのようなエレベーターラッシュがあるわけだが、社員や長めの契約社員の方は普通である。ちなみに、遅刻をするとビル下の警備員ににらまれるのである。まるで、高校生のようだw
と、ラピダスと K 社のアピール面は異なる。K 社の場合は、徹底的に合理化された営業スタイルとバックグラウンドにある営業システムに強みがある、今後もそうだろう。一方で、ラピダスの場合は(まだ成功しているわけではないが、あのロードマップを見ると、成功はしそうだ。少なくとも試作はできている)、専門知識を活用した上で、一点突破のスタイルで突き進む。まさに技術力と品質が営業力となっている。
共感というか、見込み客自身が IT 屋に発注するために、自ら見積もりができるツールの試作です。非 IT 業者向けです。OpenAI API を使っているので、ローカルで動かしてみてください。参考サイトは https://omitt-chan.vercel.app/ にあります。そもそも、どう見込み客にリーチするかどうかは問題があるのでが(苦笑)、これ、AI エージェントを使って高速プロトタイプ作成をしたらどうなるのかの一環なので、そういう意味でのお試しです。ちなみに、この React コードは内部にあるプロンプトも含めて1日程度で出来ています。
が棚に平置きになっておりました。平積みは水平に本を置くのですが、私としては棚に平置きになっているほうが嬉しいです。表紙が目の高さにあるので、平置きに目線をしたに下げるよりも、目線を上げて探すことが多いです。さらに言えば、スペース的にお得ですからね。他の本も並べられます。 どうやら、AI エージェント絡みで「spec 駆動(仕様駆動)」というワードが広がっています。いわゆる、ドキュメントに従って AI エージェントを動かそう、という話です。なんのことはない、従来型のウォーターフォール型や計画駆動を AI エージェントに置き換えただけなのですが、どうやら、最近の若い人には「仕様書を書く」ということが馴染みがないようで、仕様書の書き方がわからない、そもそも仕様や設計をまとめて書き下すことができない、という風潮があるようです。ようです、と言っているのは、目の前にしたことがない(…ことはないのですが、これは企業秘密としておきましょう、まあ、40代ぐらいの人でもできないし、60代近い人たちも、人まねでやっているだけで、理論的なことを学んでいない人が多いので、あまり、要件/仕様/設計が出来ている人はいません。アジャイルというか、カウボーイコーディングの人が多いのです。あまり関わりたいくないのですが、私の向こうがコーディングされている場合は ok です。被害を被らないし)訳でもないのですが、そのような傾向がみられます。
ああ、そういうことか、と加藤は思った。保守・運用を担当しているのだから、ちょっと位サービスをしてもよいけど、コードレビューをするにはやりすぎかなと思うし、さてどうしたものか。阿部さんの話を聞く限り、どうも「AI 駆動」に何か幻想を抱きすぎているという気がする。いや、阿部さんは解っているらしいのだけど、若手の人が問題だろう。ひょっとすると、生成 AI とか AI エージェントに過大な期待を抱いているのだろう。
AI がなんでも答えてくれるわけではない。「幻覚(ハルシネーション)」という言葉は随分一般に浸透しけど、最近の「AI 駆動」の中の spec 駆動には勘違いが多い気がする。そこは設計書や仕様書をまとめていない世代には仕方がないが。いっそんこと、AI ペアプロの形でコードレビューを AI に任せるとか、チケット駆動式に思いついた機能を少しずつ実装していくほうがいいのではないだろうか。まあ、若手のコーディングスキルがどの程度かわからないが、あまり細々としたものをこちらに持ってきてもらうよりも、内製できるツールは内製して貰ったほうがいいし、ここは、ちょっとだけ労力がかけますか。
どうやら、長島さんには何か通じたようだ。弊社では、数か月間から AI エージェントで GitHub Copilot を使っている。GitHub Copilot は、Visual Studio Code の拡張機能として動き、GitHub Pro に月10$ で加入できる AI エージェント入門編として…という宣伝文句はどうでもいいのだが、入口には Copilot がちょうどよい。一応、Claude Code もにも加入して貰って試験的に使っている。ただ、長島さんが言うには「夜中に動かすような大規模プロジェクトならば、確かにペイができるんでしょうが、うちぐらいの中小規模のプロジェクトとなると、昼間に流すことが多いので、あまり綿密な設計に踏み込まないほうが結果的に効率がよいですよね。色々ですが、いろいろ」とのことだった。
それはさておき、夜中に AI エージェントを動かして、翌日に結果をみたときにコーディングの出力が止まっていることが多いそうだ。できたとしても頓珍漢なものがでてくる。まるで、3D プリンターのもじゃもじゃのようだが、そういうこともあるだろう。仕方がない。markdown の設計書をきっちりと直して、何回か流すとできあがるらしいが、そこまで労力を掛けるものかどうかが疑問だ。
長島「加藤さん、できあがりましたよ」 加藤「おお、早いね。ええ、早いというか、数行しか経ってないのだけど、できた?」 長島「ええ、まあ、ざっと見た感じでは、というか、もとのファイルを見ても仕方がないんですけどね。*.md ファイルがたくさんあるところを見ると、細かく設計を煮詰めすぎです」 加藤「やっぱり…」 長島「AI エージェントとか AI 駆動の書籍を読むと、設計をきめ細やかにと書いてあるものが多くて、以前のウォーターフォール開発を思わせるものが多いのですが、そもそも、そんなにきっちりと設計ができる訳がないんです。というか、きちんとできないから、アジャイル開発やチケット駆動がでてきたわけで、そこを無視して、AI 駆動だけ設計をきっちりとやろうとしても無理があるんですよ」 加藤「同意見だ」 長島「専門家ならばまだしも、素人…と言っていは言い方が悪いのですが、設計書を書いたことがない若い人の場合には、もっと逐一動作確認をしながら AI コーディングを進めていったほうがいいですよ」 加藤「なるほどね。確かにね。まあ、そうだよね。で、どうする?」 長島「最初のプロンプトはこんな感じで大丈夫ですよ」
プログラミングをするときに、生成AI あるいは AI エージェントを日常的に使っている人は多いだろう。生成 AI の活用は、2年前の新人教育から使っているのが、質問事項はほぼ「AI に聞け」ということにしてある。文法を全体を網羅して覚えるよりも、基本的な書き方だけ学び、解らなかったら AI に尋ねるということが効率的である。
さらに、今年の6月頃からだったか、AI エージェントが一般的になってきた。生成 AI 単体ではなく、ファイルやプロジェクトの内容を書き変えてくれる AI エージェントの存在は、コーディングというものを一変させている。AI 駆動と言う形で、最初に細かな仕様や設計を決める向きもあるのだが、私の場合は AI ペアプロがお勧めである。AI ペアプロの話は、また別の機会にやるとして、ここでは、短編を書くときの AI 利用についてちょっと気付いたことを書いておきたい。
AI のサポートは、わざわざ AI に尋ねるのではなく、文章の続きを AI が差し込んでくれるのがむいている。特に技術書のように書き方が決まっている場合は、巷の Web サイトにある Microsoft や Google の公文書のような文体を差し込んでくれるので丁度よい。私の場合は「ですます調」で技術書を書くことにしているので、Web サイトの解説を AI が学習してくれて、それを私の文章に差し込んでくれるパターンだと、文章が無個性になって丁度よいのだ。「無個性」と言う書き方をしたが、プログラミングの本としては、ポリシーとして筆者の思惑をあまり主張しないようにしている。他の著者さんは違うかもしれないが、技術書は基本読み飛ばしが多いので、あまり文章に個性が出てしまうと読みにくくなってしまう。さらに言えば、私の悪文(多分悪文w)を編集者の方が直してくれている。読点が多いのが特徴で、語るように書くのもそうなのだが、長い文章の中で主語と述語がずれてしまうことがある。これ、語り言葉の場合はそう思えないのだけど、文章になると目立つのだ。特に、”熟読” している読者がいると、目立つ。そりゃ、文法上おかしいのだから目立ちますよね。そんなんに熱心に読まなくても大丈夫ですよ。さらっと、読み飛ばしてください。
で、生成 AI の場合は、なんとなく主語や前の文章を書くと、先の文を続けてくれる。この方式は生成 AI の Transformer に依存するものなのだが、いわゆるトークンとパラメーターの近似状態だけできまる。端的に言えば、top-p と温度というふたつの要素だけで、次の文章を決めることができる。もちろん、ランダム性が加わるので、かならずしも同じ文章になるとは限らない。そこで、ランダム性を広くとって SF 小説などを書くサポートに生成 AI をつけるとよいのである。
それと同時に、小説家にはそれなりに文体がある。例えば、2ch(あるいは 5ch)であるような村上春樹風の文章やら、星新一風の文章であるやらがそれだ。同じテーマを与えて「夏目漱石風に書いて」ということも AI には可能である。実際にどう似ているかは読むと解るのだけど、想像するに
生成 AI は近隣値(ベクトル)が近い形でトークン(単語)を選択するので、先立つ文章に続く生成される文章は、当然のことながら、学習元となる Web サイトや既存の公開されている電子文書(特に論文)に近い方になります。論文を書くとか技術文書を書く場合にはそのほうがよいでしょう。しかし、小説を書こうとなるとこれが一変します。独自性を出す、自分なりの文体を構築しようとしたときに、生成 AI がサジェッションする文章をそのまま採用することはできあません。定番の推理小説ならばいいのでしょうが、ちょっと毛色の変わった自らの文体を作りたい場合は邪魔になります。いえ、寧ろ、生成 AI がサジェッションする文章はそのまま採用できません。
先日、「百年の孤独」を買い直した。ガルシア・マルケスがノーベル賞を取ったときに買っては見たものの暫く放置の状態で、引っ越しの折にBOOK OFF に売ってしまったような覚えがある。引っ越すときに、3,000冊の本を2,000冊位に減らした時にまぎれてしまった訳だが。あまり本は捨てるものではない。とはいえ、最近は電子書籍が便利になったので、Kindleに2,000冊ほど入っている(漫画も含めてだけど)。物理本は1,000冊弱にはなったのじゃないだろうか。で、買い直したのは、先日「百年の孤独」の100分の解説だったかで、大江健三郎や筒井康隆に影響を与えたとことを知ったのである。実は「百年の孤独」は1967年の出版で、私が生まれる前だ。ああ、そんなに古い作品であったのか、というのと大江健三郎(たぶん、万延元年のフットボールか燃え上がる木あたり)に影響を与えたとか、筒井康隆(たぶん、バブリング創成期とか)に影響を与えたとかという話になると、もう一回読んでみないとあかんだろうということになる。そうなると井上ひさしの「吉里吉里人」もそうじゃないだろうか、と思う訳で。で、まだ、「百年の孤独」は読んでいないのだが。
筒井康隆の初期作品に「東海道戦争」(1965年)がある。戦争を眺めるというパターンなのだけど、「銀河鉄道999」(1977年)にも戦争を眺めて食事をするシーンがある。松本零士は筒井康隆の5つぐらい下になるが、ほぼ同世代といってよいだろう。筒井康隆が90歳で存命なわけだが、星新一、小松左京、藤子不二雄、手塚治虫、とこのあたりの SF 世代はみな鬼籍に入っていしまっている。まあ、そういう意味では、夢野久作とか沼正三とか押川春浪なんかは、さらに年上なのだけど。そういう SF の技法に沿った形で描けるのは筒井康隆しか残っていないと言える。
ただし、「朝のガスパール」や「ビアンカ・オーバースタディ」のような書き方、さらに「モナドの領域」が現在の SF 小説(ラノベも含めて)にない訳ではない。むしろ、異世界転生ものだったり、ゲーム世界の拡張であったりするストーリーはそういう「メタ」的な視点が多いに含まれているし、それを知っていることが読者/視聴者の前提知識であったりする。例えば、涼宮ハルヒシリーズであったり、Reゼロであったり、SSSS.GRIDMANであったり、このすばであったり。主人公は意図的にメタ世界を意識している。もちろん、特別な能力があったりなかったりするわけだが、そういう現実的な世界とは別の世界に居ることを前知識として知っているという仮想世界、という読者との申し合わせは済んでいる状態になる。そのあたりは、「朝のガスパール」の連載時点でも、漫画の中に作者が登場したり(Dr.スランプとか、ブラック・ジャックとか)するシーンもあり、駒からはみ出したりするシーンがある。もちろん、そこを小説/漫画内に組み込み始めたは、果たして「朝のガスパール」だったのか、それともそれ以前に漫画があったのかは定かではない。
第7章 タイムボックス 第6章のコミュニケーションに関わるものとして、締め切りを明確にした「タイムボックス」制を使います。つまり、いつまで作ればよいか?を明確にして、その間にあれこれと言わないということです。皆さん、プログラマはプロなんですから、途中でサボったりしませんよね、ということとサボっても締め切りには間に合わせてね、ってことです。途中経過は問わないのです。結果が重要です、という話ですね。 逆に言えば、未知なる要素が多いとこきはタイムボックスが有効に働きません。経験上、とあるコードが何時間、何日で作れるのかというのは「勘」を働かせることもありますが、過去の経験との比較をするのがベターです。あと、自分の実力を知るために PSP をしておくとよいです。うまくいかなそうなときは、いったんタイムボックスを外して、調査時間を決めて(時間は無限ではないので)、どのくらいで調べられそうかをチェックします。これは AI エージェントを使ったコーディングでも同じことが言えます。途中で迷路に入ってしまった AI エージェントを “時間” を区切って引き戻します。前回のプロンプトを無しにして、もう一度やり直しをすれば ok です。
CommandType Name Version Source ----------- ---- ------- ------ Application fake.exe 6.1.0.0 C:\Users\masuda\.dotnet\tools\fake.exe
バージョンはこんな感じです。
PS H:\kitami\FolkBearsGroup\folkbears-android\FolkBears> fake --version FAKE 6 - F# Make (6.1.3.0) (running on .NETCoreApp,Version=v6.0) (this line is written to standard error, see https://github.com/fsharp/FAKE/issues/2066) FakePath: C:\Users\masuda\.dotnet\tools\.store\fake-cli\6.1.3\fake-cli\6.1.3\tools\net6.0\any\Fake.Runtime.dll Paket.Core: 8.1.0
#r "paket:
nuget Fake.Core.Target
nuget Fake.Tools.Shell //"
#load "./.fake/build.fsx/intellisense.fsx"
open Fake.Core
Target.create "Clean" (fun _ ->
printfn "Cleaning..."
)
Target.create "Build" (fun _ ->
printfn "Building..."
// gradlew でビルド
Shell.Exec("./gradlew.bat", "assembleDebug") |> ignore
// Shell.Exec("gradlew", "build")
)
Target.create "Default" (fun _ ->
printfn "Default target実行中..."
printfn "gradlewでAndroidアプリをビルドします"
// gradlew でビルド
let result = Shell.Exec("./gradlew.bat", "assembleDebug")
if result = 0 then
printfn "ビルド成功"
else
printfn "ビルド失敗"
failwith "gradlewビルドが失敗しました"
)
// Android 実機にデプロイする
Target.create "Deploy" (fun _ ->
printfn "Deploying to Android device..."
Shell.Exec("./gradlew.bat", "installDevDebug") |> ignore
)
// 特定のデバイス(25041JEGR04165)にデプロイする
Target.create "DeployToDevice" (fun _ ->
printfn "Deploying to device 25041JEGR04165..."
// 環境変数でデバイスを指定
System.Environment.SetEnvironmentVariable("ANDROID_SERIAL", "25041JEGR04165")
let result = Shell.Exec("./gradlew.bat", "installDevDebug")
if result = 0 then
printfn "デプロイ成功 (25041JEGR04165)"
printfn "アプリを起動しています..."
// アプリを起動
let launchResult = Shell.Exec("adb", "-s 25041JEGR04165 shell am start -n jp.mamori_i.app.dev/jp.mamori_i.app.screen.start.SplashActivity")
if launchResult = 0 then
printfn "アプリ起動成功"
else
printfn "アプリ起動失敗"
else
printfn "デプロイ失敗"
failwith "デプロイが失敗しました"
)
// アプリを起動する(デプロイ済みの場合)
Target.create "LaunchApp" (fun _ ->
printfn "Starting app on device 25041JEGR04165..."
let result = Shell.Exec("adb", "-s 25041JEGR04165 shell am start -n jp.mamori_i.app.dev/jp.mamori_i.app.screen.start.SplashActivity")
if result = 0 then
printfn "アプリ起動成功"
else
printfn "アプリ起動失敗"
failwith "アプリ起動が失敗しました"
)
open Fake.Core.TargetOperators
// 依存関係を削除して、Defaultが単独で実行されるようにする
Target.runOrDefault "Default"
色々と書いてありますが、これは vscode 上で GitHub Copilot + Claude Sonnet を使って書き足したものです。文法はは F# なので、既存の生成 AI のモデルに学習結果が含まれています。このために、Fake の書き方も的確に書いてくれます。
vscode の拡張には、Ionide.Ionide-fsharp を入れておくと便利です。
ビルド&実機へのデプロイを試してみましょう。
fake build -t DeployToDevice
無事、ビルドとデプロイが終わると次のところまで表示がでます。
警告が出ていますが、無視して大丈夫です。
Warning: Paket resolved a FSharp.Core with version '9.0.0.0', but fake runs with a version of '8.0.0.0'. This is not supported. Please either lock the version via 'nuget FSharp.Core <nuget-version>' or upgrade fake. Read https://github.com/fsharp/FAKE/issues/2001 for details.