Compare commits

...
Sign in to create a new pull request.

456 commits

Author SHA1 Message Date
Jeremy Vyska
dbbc3d3cdc
Merge pull request #286 from microsoft/add-kine-knowledge-gap-article
Add article: AI for BC Development - The Knowledge Gap That Ships to Production
2026-04-01 11:54:55 +02:00
Jeremy Vyska
3e884878ab Add Kine article: AI Knowledge Gap That Ships to Production to vibe coding resources
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-01 09:19:07 +02:00
Jeremy Vyska
76159eb8cc
Merge pull request #283 from microsoft/agentic-assistance-hub
Orphaned files meant for the original PR
2026-01-20 14:24:42 +01:00
Jeremy Vyska
6f72c21a60 Orphaned files meant for the original PR 2026-01-20 14:23:48 +01:00
Jeremy Vyska
36c4ec1c0e
Merge pull request #275 from microsoft/issues/250
Fix #250: Clarify case sensitivity of APIPublisher and APIGroup
2025-12-16 12:24:39 +01:00
Henrik Helgesen
ed0868d8c1
Merge pull request #273 from microsoft/issues/150
Fix #150: Replace unavailable video with note
2025-12-03 12:44:37 -08:00
Henrik Helgesen
345e0f2a64
Merge pull request #274 from microsoft/issues/270
Fix #270: Add CAL Coding Guidelines PDF and fix broken link
2025-12-03 12:43:39 -08:00
Henrik Helgesen
b8d7ceccfc
Merge pull request #282 from javiarmesto/ai-native-dev-guideline
New Tool - AI Native AL Development toolkit
2025-12-03 12:37:25 -08:00
Javier Armesto Gonzalez
aa970ed0a6
Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 12:00:55 +01:00
Javier Armesto Gonzalez
0042e10d5f
Add files via upload 2025-11-28 11:00:53 +01:00
Jeremy Vyska
d2cdf97e0c
Merge pull request #279 from microsoft/jeremy-siteops
Front page updates & fixes
2025-11-10 12:48:24 +01:00
Jeremy Vyska
3a262c4d33 Refresh of front page content 2025-11-10 12:47:46 +01:00
Jeremy Vyska
9ea56d5843 Fixing broken front page link 2025-11-10 12:39:14 +01:00
Jeremy Vyska
e508cb64fb
Merge pull request #278 from microsoft/main
Updating siteops branch for small fixes
2025-11-10 12:37:43 +01:00
Henrik Helgesen
afc35a8c51
Merge pull request #265 from igor-ctrl/patch-1
Update index.md
2025-10-23 09:50:39 -07:00
Jeremy Vyska
aba9b11f07 Fix #250: Clarify case sensitivity of APIPublisher and APIGroup for subscriptions 2025-10-18 13:45:00 +02:00
Jeremy Vyska
77b968ae1f Fix #270: Add CAL Coding Guidelines PDF and update broken link 2025-10-18 13:42:14 +02:00
Jeremy Vyska
8afc5570db Fix #150: Replace unavailable video with note about missing content 2025-10-18 13:35:27 +02:00
Jeremy Vyska
2c230e308c
Merge pull request #272 from microsoft/agentic-assistance-hub
Agentic assistance hub
2025-10-17 15:19:07 +02:00
Jeremy Vyska
9055fcbbd4 Adding vibe coding to the index 2025-10-17 15:16:55 +02:00
Jeremy Vyska
d0ebcffb21 Merge remote changes - accept incoming al-upgrade.md file 2025-10-17 14:38:44 +02:00
Jeremy Vyska
e079f2b10f
Merge pull request #271 from microsoft/main
Pulling main back into Agentic
2025-10-17 14:34:31 +02:00
Jeremy Vyska
86ee402b1b Reorganizing Agentic/Vibe Section 2025-10-17 14:30:58 +02:00
Jeremy Vyska
86d86c326b Fixing broken internal links 2025-10-17 14:27:13 +02:00
Jeremy Vyska
b0ae28ffa1
Merge pull request #268 from microsoft/agentic-assistance-hub
Agentic assistance hub

Reviewed by several peers, better to get in place to improve.
2025-10-17 12:22:33 +02:00
Jeremy Vyska
907a8f3415 Clean up Articles page: remove placeholders, add CTA and quality checklist 2025-10-17 12:20:43 +02:00
Jeremy Vyska
784ef6d58d Add Waldo BC Telemetry Buddy page (summary, links) 2025-10-17 12:20:41 +02:00
Jeremy Vyska
0f61791734 Add NAB AL Tools MCP page (summary, features, links) 2025-10-17 12:20:39 +02:00
Jeremy Vyska
8a583c8edc Curate videos.md: add 4 starter videos, contributor CTA, and quality criteria 2025-10-17 12:18:50 +02:00
Jeremy Vyska
103ce14426 Add NAB AL Tools MCP server to Tools list 2025-10-17 09:22:35 +02:00
Jeremy Vyska
e6477e447d Add BC Telemetry Buddy (Waldo) to Tools list 2025-10-17 09:05:07 +02:00
Jeremy Vyska
28adab2c0a
Update creator information in documentation 2025-10-11 17:50:06 +02:00
Jeremy Vyska
b486ac7550
Merge pull request #269 from microsoft/hugo-updates
Update GitHub Actions workflow to use Hugo v0.151.0
2025-10-10 12:51:01 +02:00
Jeremy Vyska
9794f220a3 Update GitHub Actions workflow to use Hugo v0.151.0 2025-10-10 12:50:12 +02:00
Jeremy Vyska
c0ed6c9f75
Merge pull request #267 from microsoft/hugo-updates
Update Docsy to v0.12.0 for Hugo v0.151.0 compatibility
2025-10-10 12:41:15 +02:00
Jeremy Vyska
18938a0e88 Update Docsy to v0.12.0 for Hugo v0.151.0 compatibility 2025-10-10 12:40:04 +02:00
Jeremy Vyska
648d1b0bf4 Fixing menu order 2025-10-10 12:35:23 +02:00
Jeremy Vyska
4db38ba4d3 Add comprehensive agentic coding documentation
- Add 6 MCP server documentation pages (bc-code-intelligence, al-dependency, azure-devops, serena, al-objid, clockify)
- Add AI Coding Agents documentation (GitHub Copilot, Claude, Cursor)
- Add Getting Started section (what is agentic coding, setup, prompting, best practices, limitations, glossary)
- Add Getting More section (code review, documentation, telemetry examples)
- Add Community Resources placeholders (articles, videos, tools)
- Update Tools section to focus on MCP servers instead of VSCode extensions
2025-10-10 12:25:41 +02:00
Nikola Kukrika
8626051cd3
Merge pull request #266 from microsoft/features/UpgradeGuidelines
Upgrade guidelines
2025-10-09 11:18:25 +02:00
Nikola Kukrika
17f18636c7 Adding lattest instructions 2025-10-08 12:52:09 +02:00
Igor
7dd5bae8c9
Update index.md
## Update No. Series pattern for BC v24+ modern API

Microsoft deprecated `NoSeriesManagement` in BC v24+. Added modern `codeunit "No. Series"` pattern documentation with simplified API examples, comparison table, and method reference. Legacy content preserved for backward compatibility.

Real-world implementation verified in production BC extension.
2025-10-01 15:34:12 -05:00
Nikola Kukrika
4a0ab33045 Upgrade review guideliness 2025-09-16 15:44:59 +02:00
Jeremy Vyska
f82dfd03b4
Merge pull request #264 from microsoft/jeremy-siteops
Merge pull request #263 from microsoft/main - site engine updates
2025-08-11 10:16:24 +02:00
Jeremy Vyska
3254d9b7e8 Update GitHub Page deploy action 2025-08-11 10:15:56 +02:00
Jeremy Vyska
51224f6bc7
Merge pull request #263 from microsoft/main
Updating old branch to fix some actions
2025-08-11 10:15:25 +02:00
Jeremy Vyska
aa63b549fb
Merge pull request #260 from christianbraeunlich/update-upload-artifact-action
Update upload-pages-artifact to v4
2025-08-11 08:35:22 +02:00
Christian Bräunlich
0aadb75631 update upload-pages-artifact to v3 2025-08-08 23:49:08 +02:00
Arend-Jan Kauffmann
92adcb9308
Merge pull request #258 from DmitryKatson/main
Vibe Coding for AL coding rules
2025-08-08 15:31:12 +02:00
Dmitry Katson
2a805b20dc Update AL coding guidelines to use PascalCase for variable and function names
- Corrected naming conventions in the AL code style documentation to specify PascalCase instead of camelCase for variables and functions.
- Adjusted examples throughout the documentation to reflect the updated naming conventions.
- Enhanced clarity in performance guidelines by renaming procedures for better understanding.
2025-07-30 22:08:25 +08:00
Dmitry Katson
6b3f522a16 Vibe Coding for AL coding rules
- Added new rules files for Vibe Coding, including guidelines on AL code style, naming conventions, performance optimization, error handling, event-driven development, and testing.
- Updated existing links
2025-06-26 14:58:03 +07:00
Arend-Jan Kauffmann
5e76983b77
Merge pull request #249 from Busschers/ErrorHandling-ListOfReferenceText
Fixed copy-paste mistake in reference text.
2024-10-04 16:58:48 +02:00
Luuk
ec423a0428 Fixed copy-paste mistake in reference text. 2024-09-11 09:41:19 +02:00
Henrik Helgesen
917a8cb5a9
Merge pull request #239 from microsoft/dependabot/npm_and_yarn/braces-3.0.3
Bump braces from 3.0.2 to 3.0.3
2024-09-10 16:22:04 -07:00
dependabot[bot]
783975bf4c
Bump braces from 3.0.2 to 3.0.3
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-10 23:19:21 +00:00
Henrik Helgesen
fede1fd20f
Merge pull request #244 from christianbraeunlich/update-docsy-hugo-modules
Technical update is required for other PR's to be merged and published
2024-09-06 11:28:44 -07:00
Henrik Helgesen
75f3d28eeb
Merge pull request #241 from Busschers/ErrorHandling
First draft
2024-09-06 11:26:09 -07:00
Arend-Jan Kauffmann
559090d1f0
Merge pull request #237 from fvet/FVE/Removed_Semicolons
Fix formatting issues and syntax errors in code
2024-09-05 10:09:44 +02:00
Christian Bräunlich
8ba7e0dd61 remove clone step 2024-09-04 05:36:45 +00:00
Christian Bräunlich
911cf76c46 remove workflow relic 2024-09-04 05:09:15 +00:00
Christian Bräunlich
102dc94877
rearrange comment 2024-09-01 12:29:57 +02:00
Christian Bräunlich
bc536ab298 cleanup .devcontainers 2024-09-01 08:37:10 +00:00
Christian Bräunlich
1edf28aba7 fix footer_about_disabled deprecated 2024-09-01 08:33:14 +00:00
Christian Bräunlich
d4d8d0f15e update workflows 2024-09-01 08:26:36 +00:00
Christian Bräunlich
1955b65f4f update package-lock.json 2024-09-01 08:23:25 +00:00
Christian Bräunlich
6f79046b48 add node to .devcontainer features 2024-09-01 08:18:33 +00:00
Christian Bräunlich
6807e6f56e Revert "remove package.json files"
This reverts commit 6d868fb3c5.
2024-09-01 08:03:53 +00:00
Christian Bräunlich
3b4f6ed968 remove .gitmodules 2024-09-01 07:46:01 +00:00
Christian Bräunlich
6d868fb3c5 remove package.json files 2024-09-01 07:45:54 +00:00
Christian Bräunlich
70a0e69751 Removed docsy git submodule 2024-09-01 07:31:53 +00:00
Christian Bräunlich
234a95fb3f update hugo.toml theme && hugo mod graph 2024-09-01 07:30:41 +00:00
Christian Bräunlich
3df13226c3 hugo mod init github.com/microsoft/alguidelines 2024-09-01 07:30:03 +00:00
Christian Bräunlich
77c64d7670 update .devcontainers 2024-09-01 07:23:20 +00:00
Christian Bräunlich
2520893058 fix custom params on the language top level was deprecated 2024-09-01 07:21:06 +00:00
Christian Bräunlich
273de376d6 rename config.yoml to hugo.toml 2024-09-01 06:55:37 +00:00
Luuk
119b1df1c6 First draft 2024-07-10 15:59:55 +02:00
Frédéric Vercaemst
3353c5184c Fix formatting issues and syntax errors in code 2023-11-24 15:16:38 +01:00
Jeremy Vyska
8c58628b85
Merge pull request #235 from microsoft/dependabot/npm_and_yarn/postcss-8.4.31
Bump postcss from 8.4.6 to 8.4.31
2023-10-09 09:26:52 +02:00
dependabot[bot]
87ec430481
Bump postcss from 8.4.6 to 8.4.31
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.6 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.6...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-08 09:06:50 +00:00
Jeremy Vyska
00e696864b
Merge pull request #220 from PeterConijn/PatternFixes
Minor fixes to pattern pages
2023-09-28 07:14:49 +02:00
Jeremy Vyska
9812eccaf2
Merge pull request #226 from Busschers/SetLoadFIelds
SetLoadFields
2023-09-28 07:14:38 +02:00
Henrik Helgesen
6659139573
Merge pull request #234 from microsoft/TheDoubleH-patch-2
Update deployment method to Official hugo method
2023-09-22 08:18:47 -07:00
Henrik Helgesen
f88022c7f4
Update deployment method to Official hugo method
Create hugo.yml
2023-09-22 08:02:41 -07:00
Henrik Helgesen
3d1770c57b
Merge pull request #228 from eivindgiske/patch-1
Fixed broken link
2023-09-22 07:36:01 -07:00
Luuk
8befe1b704 #SetLoadFields 2023-09-22 13:01:23 +02:00
Luuk
892862e068 #SetLoadFIelds 2023-09-22 12:13:18 +02:00
Luuk
6b3d740bbb #SetLoadFields 2023-08-10 10:38:28 +02:00
Eivind Giske
cc4be1c80d
Update _index.md 2023-06-22 13:16:10 +02:00
Luuk
b317951d63 SetLoadFields 2023-06-06 10:58:57 +02:00
Luuk
6f8b7b3451 SetLoadFields 2023-06-06 10:52:52 +02:00
Jeremy Vyska
9a0922e35f
Merge pull request #219 from deadmouse/patch-1
Update index.md
2023-02-22 14:43:27 +01:00
Jeremy Vyska
f5da4182cd
Merge branch 'main' into patch-1 2023-02-22 14:43:19 +01:00
waldo
78fa831aec
Merge pull request #218 from SorenKlemmensen/patch-1
Update index.md
2023-02-22 13:16:25 +01:00
Peter Conijn
6bb60cb36f Minor fixes to pattern pages 2023-02-22 10:44:30 +01:00
deadmouse
375ef7043e
Update index.md
Repair broken links
2023-02-21 17:12:09 +01:00
Soren Klemmensen
8a4eca4d58
Update index.md
Broken link.
2023-02-20 17:28:34 +01:00
Jesper Schulz-Wedde
36e4ad4245
Merge pull request #207 from TKapitan/patch-1
No reason to use Reset for local variable
2022-11-30 13:37:22 +01:00
Tomas Kapitan
9b2c6f0c65
No reason to use Reset for local variable 2022-11-27 00:58:28 +10:00
Jeremy Vyska
254654c805
Merge pull request #204 from curateideas/dev/cl/bestpracticeKeyboardshortcuts
Dev/cl/bestpractice keyboardshortcuts
2022-09-25 20:55:59 +02:00
Christian Lenz
0c0575eec9 added shortcuts taken from BCTechDays session 2022-09-23 08:44:00 +02:00
Christian Lenz
d166fca3ea
Merge pull request #1 from microsoft/main
Merge pull request #202 from curateideas/dev/cl/bestpracticeKeyboards…
2022-09-16 10:08:51 +02:00
Jesper Schulz-Wedde
254d3a9228
Merge pull request #202 from curateideas/dev/cl/bestpracticeKeyboardshortcuts 2022-09-15 14:47:48 +02:00
Christian Lenz
49fd819565 changed design of the columns 2022-09-08 00:35:50 +02:00
Christian Lenz
77fde44ae4 added section for keyboard shortcuts 2022-09-08 00:15:59 +02:00
Jesper Schulz-Wedde
f1dd5b3ef1
Merge pull request #197 from christianbraeunlich/gitattributes
[Dev Container] add .gitattributes file
2022-07-12 10:27:07 +02:00
waldo
b1a5afb320
Merge pull request #198 from nareshwar/patch-1
Update index.md
2022-07-11 10:48:44 +02:00
Naresh
ced983249c
Update index.md
Fixed the code example with missing parenthesis.
2022-07-11 09:32:11 +01:00
Jeremy Vyska
f752d97ccc
Merge pull request #195 from sirhc101/main
Best Practice 'if-not-then-exit'
2022-07-11 09:30:51 +02:00
christianbraeunlich
2dd0a8f3c9 add .gitattributes 2022-07-01 17:38:29 +00:00
Jeremy Vyska
348c14eb80
Merge pull request #183 from christianbraeunlich/148-citation
Add Citation
2022-06-29 09:45:02 +02:00
Christoph Krieg
2c4e2cc991 Update examples 2022-06-27 19:22:33 +02:00
Christoph Krieg
3661c16c80 if not then exit 2022-06-27 19:17:15 +02:00
Jeremy Vyska
8f52709dc8
Merge pull request #189 from kine/temporary_table_safeguard
Add "Best Practice" IsTemporary record safeguard
2022-06-24 14:54:51 +02:00
ksacek
10818047ea Add "Best Practice" IsTemporary record safeguard 2022-06-22 15:36:54 +02:00
waldo
3dd196bc22 Fixed indentation (#188) 2022-06-22 11:23:49 +02:00
Henrik Helgesen
189ca1bb5f
Merge pull request #174 from PatrickSchiefer/template-method-pattern
Template method pattern
2022-06-14 16:17:28 -07:00
Patrick Schiefer
b952cc5421
Apply suggestions from code review
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-06-14 15:16:45 +02:00
Patrick Schiefer
32f0ec017f
Update content/docs/patterns/template-method-pattern/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-06-14 15:16:03 +02:00
Christian Bräunlich
b861160a51 #148 add CITATION.cff 2022-05-16 20:51:17 +02:00
Henrik Helgesen
f6a86eb60f
Merge pull request #173 from christianbraeunlich/merge-blank-lines-best-practices
[Best Practice] Merge into one Blank Lines topic
2022-05-16 11:39:20 -07:00
Christian Bräunlich
d3e38aa74a Merge branch 'main' into merge-blank-lines-best-practices 2022-05-16 20:34:46 +02:00
Henrik Helgesen
158ebff378
Merge pull request #180 from fvet/patch-4 2022-05-06 13:30:56 -07:00
Henrik Helgesen
939cfcdf9d
Merge pull request #182 from fvet/patch-6 2022-05-06 13:30:05 -07:00
Henrik Helgesen
50dc4506bb
Merge pull request #181 from fvet/patch-5 2022-05-06 13:29:20 -07:00
Henrik Helgesen
51ff02f7cd
Merge pull request #176 from christianbraeunlich/example-structure 2022-05-06 13:28:35 -07:00
Henrik Helgesen
a533a45ff2
Merge pull request #179 from fvet/patch-3 2022-05-06 13:28:09 -07:00
Henrik Helgesen
8c9b20f95f
Merge pull request #178 from fvet/patch-2 2022-05-06 13:27:26 -07:00
Henrik Helgesen
2bce340b7f
Merge pull request #177 from fvet/patch-1 2022-05-06 13:26:04 -07:00
Jeremy Vyska
3f02553645
Update content/docs/patterns/template-method-pattern/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-05-06 12:04:24 +02:00
Jeremy Vyska
f5f8983e0b
Update content/docs/patterns/template-method-pattern/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-05-06 12:04:18 +02:00
Jeremy Vyska
e9225a9ca8
Update content/docs/patterns/template-method-pattern/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-05-06 12:04:12 +02:00
Jeremy Vyska
f4b53bdd45
Update content/docs/patterns/template-method-pattern/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-05-06 12:04:06 +02:00
Frédéric Vercaemst
a1c53ccbdf
Added Tips section with link to VSCode extension 2022-05-06 09:13:50 +02:00
Frédéric Vercaemst
ee06e3d83a
Added Tips section with link to VS Code extension 2022-05-06 09:12:09 +02:00
Frédéric Vercaemst
56a903f358
Added Tips section with link to VS Code extension
#175
2022-05-06 09:09:41 +02:00
Frédéric Vercaemst
3cba72ce3f
Added Tips section with link to VS Code extension 2022-05-06 09:04:48 +02:00
Frédéric Vercaemst
0b32513b19
Added Tips section with link to VS Code extension
#153
2022-05-06 09:02:17 +02:00
Frédéric Vercaemst
a15b53e3f6
Added Tips section with link to VS Code extension 2022-05-06 09:00:32 +02:00
Christian Bräunlich
6162a121be added caption for each example 2022-05-05 16:16:27 +00:00
Patrick Schiefer
691c2fd48f Update Template method Pattern 2022-04-21 09:59:50 +02:00
Patrick Schiefer
100dffbe84 template method pattern 2022-04-21 09:44:53 +02:00
Christian Bräunlich
afc1d64ad6 updated blank lines 2022-04-15 12:59:51 +00:00
Jesper Schulz-Wedde
5652ea8c5d
Merge pull request #145 from PatrickSchiefer/commandqueue3
added command queue
2022-04-06 21:18:12 +02:00
Jesper Schulz-Wedde
32ec19fcde
Merge pull request #154 from christianbraeunlich/feature/guideline-blank-lines
Best Practice: Avoid too many Blank Lines
2022-04-06 21:16:32 +02:00
Christian Bräunlich
ae3a259f58
update example headers 2022-04-05 23:06:54 +02:00
Henrik Helgesen
155be51972
Merge pull request #160 from christianbraeunlich/feature/when-not-to-use-blank-lines
Best Practice: When not to use blank lines
2022-04-05 09:34:22 -07:00
Jeremy Vyska
9a6f6e5b8b
Very minor language tweaks
Otherwise, solid :)
2022-04-05 14:31:07 +02:00
waldo
17f423f02c
Merge pull request #170 from christianbraeunlich/patch-1
correct sentence
2022-04-05 14:17:18 +02:00
Christian Bräunlich
0bed50ad01
correct sentence 2022-04-02 18:29:51 +02:00
waldo
3684393375
Merge pull request #167 from StefanMaron/patch-1
Added Rec. to the API Page code Example
2022-03-30 11:28:08 +02:00
Stefan Maroń
6b80f47379
Added Rec. to the API Page code Example 2022-03-30 09:45:26 +02:00
christianbraeunlich
b20535245b added suggestions by TheDoubleH 2022-03-26 09:11:01 +01:00
Jeremy Vyska
1653ec32cc
Merge pull request #156 from christianbraeunlich/feature/correct-sentences
Correct sentences
2022-03-25 16:08:58 +01:00
Jeremy Vyska
6dc0ae6f2d
Merge pull request #159 from christianbraeunlich/hotfix/indentation-in-best-practice
Added indentation for best practices
2022-03-25 16:08:04 +01:00
Henrik Helgesen
417cc2f025
Update content/docs/BestPractices/CustomTelemetry/index.md
Removed the word period
2022-03-24 14:50:26 -07:00
christianbraeunlich
6915945e92 added when-not-to-use-blank-lines 2022-03-19 23:04:56 +01:00
christianbraeunlich
83053e7287 added indentation 2022-03-19 22:12:39 +01:00
christianbraeunlich
0c5f3b319d added captions 2022-03-19 21:35:07 +01:00
christianbraeunlich
16aaca3614 added some blank lines examples 2022-03-19 20:54:06 +01:00
christianbraeunlich
7cf65b3d3b initial "avoid too many blank lines" best practice 2022-03-17 23:03:42 +01:00
christianbraeunlich
42358aab34 added period at the end 2022-03-17 21:56:01 +01:00
christianbraeunlich
bb587c5d09 change wit to with 2022-03-17 21:49:35 +01:00
Henrik Helgesen
4fbfc28c9e
Merge pull request #142 from waldo1001/main
Cosmetic changes
2022-03-11 03:04:35 -08:00
Patrick Schiefer
f892465759 Descpription 2022-03-09 16:18:49 +01:00
Patrick Schiefer
19ca096afe Update Description 2022-03-09 16:16:29 +01:00
Jeremy Vyska
ed09a81f6a
Merge pull request #146 from christianbraeunlich/feature/mermaid
Docsy - Diagrams with Mermaid
2022-03-08 09:08:58 +01:00
Christian Bräunlich
75dd79f904
added mermaid to formatting tips 2022-03-06 18:22:58 +01:00
Christian Bräunlich
d5fb3894ec
added mermaid feature 2022-03-06 17:49:23 +01:00
Patrick Schiefer
f40daf4b1f added command queue 2022-03-05 19:43:29 +01:00
waldo
b8b9b16998
Merge pull request #143 from tfenster/main
Support devcontainer (local and GH Codespaces)
2022-03-02 15:31:58 +01:00
Tobias Fenster
408368b3de
add initial checks if it doesn't work 2022-03-02 12:28:41 +01:00
Tobias Fenster
cda4104e61 add explanation for switching 2022-03-02 10:54:35 +00:00
waldo
78d169687a
Update content/docs/BestPractices/CustomTelemetry/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-03-02 10:04:47 +01:00
Tobias Fenster
99e883f0c6
change headline level 2022-03-02 07:34:15 +01:00
Tobias Fenster
e8a856f625 docs for devcontainer 2022-03-01 23:39:41 +00:00
Tobias Fenster
faf2dbdc0a weird error 2022-03-01 22:26:20 +00:00
Tobias Fenster
819d05a9ca add npm on init 2022-03-01 22:20:58 +00:00
Tobias Fenster
9cdaaf3a39 add support for devcontainers and direct run 2022-03-01 22:17:44 +00:00
waldo
bfc249435d Cosmetic changes 2022-03-01 16:40:01 +01:00
waldo
c2804fc330
Merge pull request #141 from TheDoubleH/main
Update Front Page 'Whats New'
2022-03-01 09:30:09 +01:00
Henrik Helgesen
798ed63b53 Update Front Page 'Whats New' 2022-02-28 14:04:33 -08:00
waldo
d2725b5bf0
Merge pull request #139 from microsoft/jv/no-series
Revived Pattern: Number Series
2022-02-28 22:40:28 +01:00
Jeremy Vyska
a4a46ab85a Added Journal NoSeries info 2022-02-27 22:09:51 +01:00
Jeremy Vyska
24f04c7fda Fixing formatting, adding clarity, WITH warn 2022-02-27 21:48:06 +01:00
Jeremy Vyska
9b97d1151e
Update content/docs/patterns/no-series/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-02-27 21:28:29 +01:00
Jeremy Vyska
d7792f5489
Update content/docs/patterns/no-series/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-02-27 21:28:21 +01:00
Jeremy Vyska
ccbf573ec8
Update content/docs/patterns/no-series/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-02-27 21:28:15 +01:00
Jeremy Vyska
8543650944
Update content/docs/patterns/no-series/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-02-27 21:27:58 +01:00
Henrik Helgesen
13beb2fee6
Correct Typo
Tags are not tages
2022-02-27 11:23:04 -08:00
Henrik Helgesen
7f492b2c47
Merge pull request #137 from microsoft/ajk/api-register-fieldset
New pattern API Register Fieldset
2022-02-27 11:15:08 -08:00
Henrik Helgesen
615864e950
Merge pull request #136 from microsoft/ajk/delegate-api-operation
Pattern added Delegate API operation
2022-02-27 11:13:04 -08:00
Henrik Helgesen
8424546db5
Merge pull request #135 from microsoft/ajk/api-page
New guideline API page
2022-02-27 11:10:28 -08:00
Henrik Helgesen
58db3a3a3c
Merge pull request #138 from microsoft/waldo/somechanges
Add AuthorName - just because we can ;-)
2022-02-27 10:59:14 -08:00
Jeremy Vyska
2ba8365e37 Revived Pattern: Number Series 2022-02-27 17:41:39 +01:00
waldo1001
8503a84609 Add AuthorName - just because we can ;-) 2022-02-27 16:37:58 +01:00
waldo
c41d4e9e24
Merge pull request #134 from microsoft/ajk/CustomTelemetry
Add guideline CustomTelemetry
2022-02-27 15:08:19 +01:00
Arend-Jan Kauffmann
496f1a6b47 New pattern API Register Fieldset 2022-02-27 00:01:34 +01:00
Arend-Jan Kauffmann
55a705376f Pattern added Delegate API operation 2022-02-26 22:44:51 +01:00
Arend-Jan Kauffmann
2ec683b653 New guideline API page 2022-02-26 20:59:34 +01:00
Arend-Jan Kauffmann
fb6a07a1ee Resolve comments + extra chapter 2022-02-26 17:05:49 +01:00
Arend-Jan Kauffmann
bc45439b53 Add guideline CustomTelemetry 2022-02-25 23:13:54 +01:00
Henrik Helgesen
80b377d382
Merge pull request #125 from TheDoubleH/InstallHugoOnWindows11
Install hugo on windows11
2022-02-25 08:46:22 -08:00
Henrik Helgesen
1486266329
Merge branch 'main' into InstallHugoOnWindows11 2022-02-25 08:45:57 -08:00
Henrik Helgesen
1e5fd62577
Merge pull request #133 from TheDoubleH/CleanupDiscussion
Removed Discussion Links. Using new Theme solution.
2022-02-25 08:45:12 -08:00
Henrik Helgesen
fb17dc9640 Removed Discussion Links. Using new Theme solution.
Some additional MDLint cleanup as well
2022-02-24 15:36:06 -08:00
Henrik Helgesen
cd3497d542
Merge pull request #126 from microsoft/docsy-theme-redo
Revert site logo to official Microsoft iconography
2022-02-24 14:25:57 -08:00
Arend-Jan Kauffmann
d6a2ff9437
Merge pull request #127 from microsoft/waldo_tags
Added tags & categories + cleanup
2022-02-24 22:02:48 +01:00
Jeremy Vyska
917c31fa8c Style improvements 2022-02-24 21:56:08 +01:00
Jeremy Vyska
32273fd1ec Github Link section revision 2022-02-24 21:49:57 +01:00
waldo
743886be65
Merge pull request #128 from microsoft/waldo1001-patch-2
Update _index.md
2022-02-24 21:06:46 +01:00
waldo
5e676054d9
Update _index.md 2022-02-24 21:06:30 +01:00
Henrik Helgesen
44f4036e67 Merge branch 'main' into InstallHugoOnWindows11 2022-02-24 11:29:53 -08:00
waldo1001
5ee0436639 Added tags & categories + cleanup 2022-02-24 14:45:35 +01:00
Henrik Helgesen
a5ea50694e Merge branch 'InstallHugoOnWindows11' of https://github.com/TheDoubleH/alguidelines into InstallHugoOnWindows11 2022-02-24 02:42:16 -08:00
Henrik Helgesen
d521d3baa8 Install via Powersehll 2022-02-24 02:42:12 -08:00
Jeremy Vyska
ee09ec590d
Update _index.md
A few small proofreading tweaks, but otherwise looks solid.
2022-02-24 07:46:26 +01:00
Jeremy Vyska
05c86e17a0 Revert site logo to official Microsoft iconography 2022-02-24 07:39:39 +01:00
Henrik Helgesen
5a85dcee51 Remove extra blank line 2022-02-23 15:30:46 -08:00
Henrik Helgesen
b15b08473b Install Hugo on Win 11 2022-02-23 15:26:56 -08:00
waldo
4515a721bd
Merge pull request #124 from microsoft/waldo1001-patch-1
Update _index.md
2022-02-23 23:43:09 +01:00
waldo
99c7e5ebe5
Update _index.md 2022-02-23 19:02:04 +01:00
Henrik Helgesen
c995aa42da MD Lint Cleanup / Added Discussion Links 2022-02-23 01:09:10 -08:00
Jeremy Vyska
dc63c56067
Merge pull request #122 from microsoft/docsy-theme-redo
Aesthetic adjustments
2022-02-23 07:32:04 +01:00
Jeremy Vyska
8157a3c268 CSS bugfix 2022-02-23 07:31:30 +01:00
Jeremy Vyska
1470a75676 Restore spacers 2022-02-23 07:31:03 +01:00
Jeremy Vyska
322ce9cc55
Merge pull request #121 from microsoft/docsy-theme-redo
Waldo req: Remove 'waves' separator
2022-02-22 09:38:12 +01:00
Jeremy Vyska
6cb00b0350 Waldo req: Remove 'waves' separator 2022-02-22 09:37:34 +01:00
Henrik Helgesen
ea9d99f3bb
Merge pull request #120 from TheDoubleH/TemplateChangesForDocsy 2022-02-22 00:01:58 -08:00
Henrik Helgesen
eb783b94ff Cleanup and fix link 2022-02-21 23:29:23 -08:00
Henrik Helgesen
22bceb1484 Update Templates for Docsy and synced them up 2022-02-21 22:57:39 -08:00
Jeremy Vyska
70ab70dffa
Merge pull request #119 from microsoft/docsy-theme-redo
Branch rename in the config
2022-02-21 15:50:50 +01:00
Jeremy Vyska
e746cb3834 Branch rename in the config 2022-02-21 15:49:50 +01:00
Jeremy Vyska
984652dc9d
Merge pull request #118 from microsoft/docsy-theme-redo
Docsy theme adjustments
2022-02-21 15:45:29 +01:00
Jeremy Vyska
8cff4e68ab Something in the Hugo multilang not behaving 2022-02-21 15:43:42 +01:00
Jeremy Vyska
2c991534ed Re-enable search 2022-02-21 15:43:06 +01:00
Jeremy Vyska
10d929b57b
Merge pull request #117 from microsoft/docsy-theme-redo
Mobile layout repairs
2022-02-21 07:40:09 +01:00
Jeremy Vyska
06d36bef49 Tidy up Community Cards on mobile 2022-02-21 07:39:07 +01:00
Jeremy Vyska
6e7dce0943 Make header lovely on mobile 2022-02-21 07:38:48 +01:00
Jeremy Vyska
d7a7d2459a
Merge pull request #116 from microsoft/docsy-theme-redo
Need another NPM module for build
2022-02-20 21:12:21 +01:00
Jeremy Vyska
57fe5f8de2 Need another NPM module for build 2022-02-20 21:11:51 +01:00
Jeremy Vyska
52882c9db2
Merge pull request #115 from microsoft/docsy-theme-redo
Build action adjustment for submodules
2022-02-20 21:09:13 +01:00
Jeremy Vyska
91fe61d0ff Build action adjustment for submodules 2022-02-20 21:08:12 +01:00
Jeremy Vyska
47fe0a1fe4
Merge pull request #114 from microsoft/docsy-theme-redo
Docsy theme redo
2022-02-20 21:07:04 +01:00
Jeremy Vyska
c259acce6f Tweaks to the contributing page 2022-02-20 21:03:39 +01:00
Jeremy Vyska
3d0cb3a40b Moving contributing 2022-02-20 20:58:53 +01:00
Jeremy Vyska
871c538bfd Massive rework and beautification 2022-02-20 20:55:49 +01:00
Jeremy Vyska
cceb0c945e Restructure for Docsy theme 2022-02-20 13:18:49 +01:00
Jeremy Vyska
f4a1ebc077 Complete Theme Migration from Henrik 2022-02-20 13:06:34 +01:00
Jeremy Vyska
eee9b2b2c1
Merge pull request #110 from microsoft/EventBridgePatten
Event Bridge Patten
2022-02-15 22:04:57 +01:00
Jeremy Vyska
e0b0cff2f0
Merge pull request #108 from microsoft/DeleteAll
DeleteAll #107
2022-02-15 22:04:46 +01:00
Jeremy Vyska
b8be6ed4b3
Merge pull request #105 from microsoft/Subscriber-Codeunits
Subsciber Codeunits #92
2022-02-15 22:04:37 +01:00
waldo
554f1c0edd
Update content/BCBestPractices/Performance/SubscriberCodeunits/index.md
Co-authored-by: Henrik Helgesen <henrik@helgesen.consulting>
2022-02-12 10:02:24 +01:00
Henrik Helgesen
9e06f72056
Merge pull request #101 from christianbraeunlich/nav-dp-formatting
NAVPatterns Formatting
2022-02-11 09:29:35 -08:00
waldo1001
faeb978e15 changed discussions 2022-02-10 23:55:30 +01:00
waldo1001
543f96b6ed Merge branch 'EventBridgePatten' of https://github.com/microsoft/alguidelines into EventBridgePatten 2022-02-10 23:50:31 +01:00
waldo1001
812ec06441 changed discussions 2022-02-10 23:50:22 +01:00
waldo
49e20f6e72
Update content/BCPatterns/event-bridge-pattern/index.md
Co-authored-by: Christian Bräunlich <sundowneffect@gmail.com>
2022-02-10 23:30:21 +01:00
waldo1001
15c06bd0b2 cleanup 2022-02-10 17:01:08 +01:00
waldo1001
28dde8ce6f cleanup 2022-02-10 16:25:01 +01:00
waldo1001
1d005b332d cleanup 2022-02-10 16:24:39 +01:00
waldo1001
04b4569f6a cleanup 2022-02-10 16:23:52 +01:00
waldo
b80bf681a4
Merge pull request #104 from christianbraeunlich/103-colon-in-headings
Remove colon in headings
2022-02-10 16:20:44 +01:00
waldo1001
19020978ad authors 2022-02-10 16:20:19 +01:00
waldo
74b163cc48
Merge pull request #111 from christianbraeunlich/typo-free
Fixed Typo fee to free
2022-02-10 16:18:36 +01:00
waldo1001
537b7caf24 Event Bridge Patten 2022-02-10 16:06:55 +01:00
christianbraeunlich
a355c847d9 fixed typo 2022-02-10 16:06:41 +01:00
waldo1001
9ddd834295 DeleteAll #107 2022-02-10 14:08:28 +01:00
waldo1001
9026d6aaae Subsciber Codeunits 2022-02-10 13:59:35 +01:00
christianbraeunlich
9d709f8d3a removed colon in headings 2022-02-07 18:10:26 +01:00
christianbraeunlich
14ac0bf363 replaced \_ by _ 2022-02-05 20:10:43 +01:00
christianbraeunlich
b426977b42 formatted \[ to [ and \] to ] 2022-02-05 19:55:53 +01:00
christianbraeunlich
2fc21159de replaced <\> to <> 2022-02-05 19:50:32 +01:00
christianbraeunlich
f1f4aab1d7 formatted nav patterns 2 to 4 2022-02-05 19:44:44 +01:00
christianbraeunlich
2fad891a77 formatted nav patterns 2022-02-05 18:19:26 +01:00
Jesper Schulz-Wedde
38a19d75d8
Merge pull request #70 from microsoft/waldo/GuidelineCaseActions
CASE Action on next line
2021-12-15 10:07:52 +01:00
Jesper Schulz-Wedde
0652b72824
Merge pull request #89 from StefanMaron/main
Cosmetic changes to the readability pages
2021-12-15 10:07:04 +01:00
Stefan Maroń
b20f5ffb41
Spaces after comma 2021-12-15 08:07:28 +01:00
Stefan Maroń
9b7917e484
Space after comma 2021-12-15 08:05:45 +01:00
Stefan Maroń
0de6d15d69
spaces after commas 2021-12-15 08:03:19 +01:00
Stefan Maroń
bc38408c78
Removed spaces 2021-12-15 08:02:08 +01:00
Stefan Maroń
4f0394811d
removed spaces 2021-12-15 08:00:19 +01:00
Stefan Maroń
0fde42cc6e
calling a procedure without parameters should have empty () 2021-12-15 07:59:20 +01:00
Stefan Maroń
34c84872b8
casing of TRUE is not the point of this bad code example 2021-12-15 07:57:45 +01:00
Stefan Maroń
8bbfe01ede
sadly, exit with () does not compile 2021-12-15 07:56:09 +01:00
Stefan Maroń
ff48e1a941
sadly, exit with empty () does not compile 2021-12-15 07:55:39 +01:00
Stefan Maroń
fc2f78581f
a comma should be followed by a space 2021-12-15 07:54:59 +01:00
Stefan Maroń
03c328bef9
end; should also have a begin 2021-12-15 07:53:24 +01:00
Stefan Maroń
a83d00e8a2
Updated some casing mistakes 2021-12-15 07:49:06 +01:00
waldo
72134d6af8
Merge pull request #88 from microsoft/waldo/discussions
"Discussions" menu item
2021-12-15 06:24:37 +01:00
waldo
1a9a488a12 "Discussions" menu item 2021-12-15 06:22:32 +01:00
Henrik Helgesen
4e0008525e
Merge pull request #76 from microsoft/waldo/guidelineLineStartKeywords
Line Start Keywords
2021-12-14 13:32:20 -08:00
Henrik Helgesen
56ac137f7c
Merge pull request #72 from microsoft/waldo/guidelineEndElsePair
end else pair
2021-12-14 13:31:13 -08:00
waldo
21bb12f665 added "()" 2021-12-14 22:30:32 +01:00
Henrik Helgesen
54c74dfd7e
Merge pull request #85 from microsoft/waldo/guidelineUnnecessaryTrueFalse
Unnecessary true/false
2021-12-14 13:29:49 -08:00
Henrik Helgesen
d0bbfcebed
Merge pull request #71 from microsoft/waldo/guidelineCommentsSpacing
Comment Spacing
2021-12-14 13:24:25 -08:00
Henrik Helgesen
525a7cd398
Merge pull request #69 from microsoft/waldo/guidelineBinaryOperatorToStartLine
Binary Operator to Start Line
2021-12-14 13:22:11 -08:00
Henrik Helgesen
da9359cdb0
Merge pull request #68 from microsoft/waldo/NewGuidelines
Moved guidelines.. .
2021-12-14 13:21:16 -08:00
Henrik Helgesen
6181d444c2
Merge pull request #75 from microsoft/waldo/guidelineKeywordPairsIndentation
Keyword Pairs - Indentation
2021-12-14 13:20:42 -08:00
Henrik Helgesen
3e49426a15
Merge pull request #77 from microsoft/waldo/guidelineLonelyRepeat
Lonely Repeat
2021-12-14 12:55:05 -08:00
Henrik Helgesen
9ee8dc872d
Merge pull request #79 from microsoft/waldo/guidelineNamedInvocations
Named Invocations
2021-12-14 12:54:09 -08:00
Henrik Helgesen
7bf3b0fe6f
Merge pull request #80 from microsoft/waldo/guidelineOneStatementPerLine
One Statement Per Line
2021-12-14 12:53:04 -08:00
Henrik Helgesen
eab45dbd91
Merge pull request #81 from microsoft/waldo/guidelineSeparateIfAndElse
Separate if and else
2021-12-14 12:50:25 -08:00
Henrik Helgesen
6a6e22433a
Merge pull request #82 from microsoft/waldo/guidelineSpacingBinaryOperators
Spacing Binary Operators
2021-12-14 12:46:56 -08:00
Henrik Helgesen
bd32e3f1ac
Merge pull request #83 from microsoft/waldo/guidelineSuggestedAbbreviations
Suggested Abbreviations
2021-12-14 12:44:40 -08:00
Henrik Helgesen
99cbd91ba4
Merge pull request #84 from microsoft/waldo/guidelineUnnecessaryElse
Unnecessary 'else'
2021-12-14 12:42:52 -08:00
Henrik Helgesen
dd680561a2
Merge pull request #86 from microsoft/waldo/guidelineVariableNaming
Variable Naming
2021-12-14 12:39:06 -08:00
Henrik Helgesen
1a7defb1d3
Merge pull request #87 from microsoft/waldo/guidelineVariablesDeclarationsOrder
Variables Declarations Order
2021-12-14 12:38:16 -08:00
waldo
4eb73cb8d3 corrected the code 2021-12-14 11:50:50 +01:00
waldo1001
f4cdeab2db Requested changes 2021-12-13 17:38:22 +01:00
waldo1001
de8c4b0241 Added End statement 2021-12-13 17:17:14 +01:00
waldo1001
32e73b30ee requested change 2021-12-13 17:16:07 +01:00
waldo1001
6877f439e9 requested change 2021-12-13 17:12:15 +01:00
waldo1001
930383d6b5 Quite 2021-12-13 17:09:19 +01:00
waldo1001
43206f9cb3 Requested change 2021-12-13 17:08:35 +01:00
waldo1001
4f3dda781e Requested change 2021-12-13 17:07:37 +01:00
waldo1001
d5f6816829 Requested changes 2021-12-13 16:31:51 +01:00
waldo1001
a1438deb71 Variables Declarations Order 2021-12-12 00:22:08 +01:00
waldo1001
090d8ae5d5 Variable Naming 2021-12-12 00:18:52 +01:00
waldo1001
0a4adb7797 Unnecessary true/false 2021-12-11 14:11:33 +01:00
waldo1001
47cb851e72 Unnecessary 'else' 2021-12-11 14:07:37 +01:00
waldo1001
ed441baceb Suggested Abbreviations 2021-12-11 14:02:31 +01:00
waldo1001
2a1d252e4a Spacing Binary Operators 2021-12-11 13:51:25 +01:00
waldo1001
5d285bcc11 Separate if and else 2021-12-11 13:46:32 +01:00
waldo1001
6863d03608 One Statement Per Line 2021-12-11 13:41:01 +01:00
waldo1001
c1b863500c Named Invocations 2021-12-11 13:37:44 +01:00
waldo1001
3ce9bb37ec Merge branch 'main' into waldo/NewGuidelines 2021-12-11 13:33:00 +01:00
waldo1001
17d2854f0d Move 2021-12-11 13:32:12 +01:00
waldo1001
e3abd7bad9 Merge branch 'main' into waldo/guidelineBinaryOperatorToStartLine 2021-12-11 13:31:54 +01:00
waldo1001
a1a476e98b Move 2021-12-11 13:31:41 +01:00
waldo1001
8b85272d9b Merge branch 'main' into waldo/GuidelineCaseActions 2021-12-11 13:31:28 +01:00
waldo1001
fc88ff781d Move 2021-12-11 13:30:49 +01:00
waldo1001
d32f36875b Merge branch 'main' into waldo/guidelineCommentsSpacing 2021-12-11 13:30:38 +01:00
waldo1001
4901cf9799 Move 2021-12-11 13:29:23 +01:00
waldo1001
3687268c91 Merge branch 'main' into waldo/guidelineEndElsePair 2021-12-11 13:29:10 +01:00
waldo1001
39340ca56d Move 2021-12-11 13:28:59 +01:00
waldo1001
a6cad1b82f Merge branch 'main' into waldo/guidelineKeywordPairsIndentation 2021-12-11 13:28:45 +01:00
waldo1001
0165f89090 Move 2021-12-11 13:28:27 +01:00
waldo1001
b0807c0f2d Merge branch 'main' into waldo/guidelineLineStartKeywords 2021-12-11 13:28:04 +01:00
waldo1001
74ce964a3a Move 2021-12-11 13:27:48 +01:00
waldo1001
d0e0027a6a Merge branch 'main' into waldo/guidelineLonelyRepeat 2021-12-11 13:27:29 +01:00
waldo
932a7adbd4
Merge pull request #78 from microsoft/waldo/guildelinesReadability
ReadabilitySubsection
2021-12-11 13:26:46 +01:00
waldo1001
3ad0ad17c7 ReadabilitySubsection 2021-12-11 13:26:16 +01:00
waldo1001
cba90ffd3a Lonely Repeat 2021-12-11 13:23:56 +01:00
waldo1001
1640719b7a Line Start Keywords 2021-12-11 13:09:18 +01:00
waldo1001
63551463a0 Keyword Pairs - Indentation 2021-12-11 13:04:15 +01:00
waldo1001
50505a5dc5 end else pair 2021-12-11 08:59:22 +01:00
waldo1001
a8d3fb3089 Comment Spacing 2021-12-11 08:54:31 +01:00
waldo1001
b4f8bfd324 CASE Action on next line 2021-12-11 08:50:31 +01:00
waldo1001
36c7a39dd1 Binary Operator to Start Line 2021-12-11 08:44:12 +01:00
waldo1001
0c48ac5ad5 Begin-End - Compound Only 2021-12-11 08:29:14 +01:00
waldo1001
36bee5f75f Small changes to the template for guidelines 2021-12-11 08:16:43 +01:00
waldo1001
d05bf6bbe4 Microsoft 2021-12-11 08:15:52 +01:00
waldo1001
a63b1597d8 begin as an 'After Word' 2021-12-11 08:14:24 +01:00
Jeremy Vyska
8f41c13f0f
Merge pull request #56 from christianbraeunlich/apply-hugo-formatting
Apply hugo formatting
2021-12-05 22:23:19 +01:00
christianbraeunlich
f88c06332c change nav 3-cal-coding-guidelines formatting 2021-12-05 20:01:22 +01:00
christianbraeunlich
bbfce1f9dc change nav 2-anti-patterns formatting 2021-12-05 19:24:06 +01:00
christianbraeunlich
7e4e21d223 change nav 1-patterns formatting 2021-12-05 19:02:27 +01:00
Henrik Helgesen
ba12637e35
Merge pull request #49 from IceOnly/generic-method-pattern/isHandled
generic-method-pattern: Handled replaced by IsHandled
2021-12-04 16:05:06 -08:00
Thomas Williamson
adb65ef1ac Handled replaced by IsHandled 2021-12-03 16:06:27 +01:00
Jeremy Vyska
10a2d6899e
Merge pull request #47 from microsoft/jeremy-siteops
Missing line break, made odd formatting
2021-12-02 16:40:49 +01:00
Jeremy Vyska
091787e79f Missing line break, made odd formatting 2021-12-02 16:40:19 +01:00
waldo
9d49a2dc82
Merge pull request #46 from tino-teuber/typo-fix
Fixed a few typos
2021-12-01 15:50:24 +01:00
Tino Teuber
7e7509dbf9 Fixed a few typos 2021-12-01 14:19:47 +01:00
waldo
eb22cb6cb7
Merge pull request #43 from microsoft/waldo/discussions2
Added discussions
2021-11-22 08:37:11 +01:00
waldo
83412cdd1e Added discussions 2021-11-22 08:35:29 +01:00
Henrik Helgesen
ed86080506
Merge pull request #39 from microsoft/FacadePattern
Initial draft of the facade pattern
2021-11-20 11:42:44 -08:00
Jesper Schulz-Wedde
79e0e16cb2 Fixing the sample code documentation. 2021-11-20 10:30:21 +01:00
Jesper Schulz-Wedde
210e83ea1e Minor corrections. 2021-11-20 10:05:41 +01:00
Jesper Schulz-Wedde
698671e061 Initial draft of the facade pattern. 2021-11-20 09:39:09 +01:00
waldo
cb9f3051eb
Merge pull request #32 from TheDoubleH/fix/PullRequestGuide
Minor Updates to Contribution
2021-11-19 18:26:01 +01:00
TheDoubleH
df757015fc Correct link 2021-11-19 08:28:59 -08:00
waldo
6c1f15c278
Merge pull request #27 from waldo1001/main
Generic Method Pattern
2021-11-19 17:08:56 +01:00
Henrik Helgesen
8448724c3c
Merge branch 'main' into fix/PullRequestGuide 2021-11-19 07:58:59 -08:00
Henrik Helgesen
d27e1d579b
Merge pull request #33 from Mkublbock/fix/broken-link
Fixed: Broken Link in Fork and PR index.md
2021-11-19 07:35:37 -08:00
Jeremy Vyska
0243955ac5
Forgot to remove template from README file 2021-11-19 16:10:12 +01:00
waldo1001
c5b412f910 Added "Usage" 2021-11-19 14:43:28 +01:00
waldo1001
302645c5d9 Processed feedback from @ajkauffmann 2021-11-19 12:04:31 +01:00
Matthias Küblböck
bfe44d2141
Fixed: Broken Link in Fork and PR index.md
Link was encased in brackets and ) was added and the end of the link resulting in a broken link - fixed by escaping the last character
2021-11-19 11:04:31 +01:00
Henrik Helgesen
34e4cae27e
Merge pull request #31 from TheDoubleH/fix/logopointtoincorrectlocation
Resolved Incorrect Link
2021-11-19 01:15:16 -08:00
TheDoubleH
4ee1399dfd Minor Changes suggested by @SimonofHH 2021-11-19 01:09:48 -08:00
Henrik Helgesen
597baa1d4c
Merge branch 'microsoft:main' into fix/logopointtoincorrectlocation 2021-11-19 01:01:43 -08:00
Henrik Helgesen
d4382c9e18
Merge pull request #29 from TheDoubleH/main
Initial Guide to Fork to Pull Request guide
2021-11-19 01:00:14 -08:00
TheDoubleH
340e105c73 Merge branch 'fix/logopointtoincorrectlocation' of https://github.com/TheDoubleH/alguidelines into fix/logopointtoincorrectlocation 2021-11-19 00:51:47 -08:00
TheDoubleH
e9c842a6a2 Removed svg logo 2021-11-19 00:51:40 -08:00
Henrik Helgesen
5263fb012e
Delete .hugo_build.lock 2021-11-19 00:48:23 -08:00
TheDoubleH
bbb685af36 Removed svg logo 2021-11-19 00:46:13 -08:00
TheDoubleH
e1e2234dc8 Resolved Logo linking to incorrect location 2021-11-19 00:44:18 -08:00
waldo1001
4862bb460f Improved thanks to SimonOfHH 2021-11-19 09:23:17 +01:00
TheDoubleH
eda83d13e7 Initial Guide to Fork to Pull Request guide 2021-11-18 23:53:53 -08:00
waldo1001
fb62a8bf24 v1 of the pattern 2021-11-18 22:23:52 +01:00
waldo1001
e48e7d8a77 Generic Method Pattern - Initial Commit 2021-11-16 23:54:34 +01:00
Henrik Helgesen
7437fbfc07
Merge pull request #25 from microsoft/waldo/prettifications
Added Henrik's blog
2021-11-16 14:22:16 -08:00
waldo
fd67d27421 Added Henrik's blog 2021-11-16 23:16:40 +01:00
Henrik Helgesen
7da313b7c6
Corrected code fencing 2021-11-16 09:44:12 -08:00
waldo
c80095ea95
Merge pull request #24 from microsoft/waldo/prettifications
I think is is better - not sure what you think ;-)
2021-11-15 23:22:15 +01:00
waldo1001
4b30149c73 I think is is better - not sure what you think ;-) 2021-11-15 23:22:00 +01:00
waldo
28eab4a5a0
Merge pull request #23 from microsoft/waldo/prettifications
Small changes
2021-11-11 14:59:15 +01:00
waldo1001
6913f75f7f Small changes 2021-11-11 14:58:48 +01:00
waldo
2676b55e22
Merge pull request #22 from microsoft/waldo/prettifications
Attempt 3 to fix shortcode description
2021-11-11 14:52:29 +01:00
waldo1001
38386ff9ff Attempt 3 to fix shortcode description 2021-11-11 14:52:12 +01:00
waldo
c19c60ae49
Merge pull request #21 from microsoft/waldo/prettifications
Fixed shortcode-description
2021-11-11 14:49:53 +01:00
waldo1001
e5f409e5e0 Fixed shortcode-description 2021-11-11 14:49:11 +01:00
waldo
12fe4a3e1b
Merge pull request #20 from microsoft/waldo/prettifications
Fixed shortcode description
2021-11-11 14:45:40 +01:00
waldo1001
2720a98145 Fixed shortcode description 2021-11-11 14:44:46 +01:00
waldo
cf0ecbda4d
Merge pull request #19 from microsoft/waldo/prettifications
Waldo/prettifications
2021-11-11 14:35:16 +01:00
waldo1001
6c65393054 Merge branch 'waldo/prettifications' of https://github.com/microsoft/alguidelines into waldo/prettifications 2021-11-11 14:34:42 +01:00
waldo1001
41f1c7ccea Formatting tips - First Draft 2021-11-11 14:34:35 +01:00
waldo1001
b6ef445d2e Formatting tips - First Draft 2021-11-11 14:34:12 +01:00
waldo
a84fbbda82
Merge pull request #18 from microsoft/waldo/prettifications
Fixed some linkes (I hope)
2021-11-11 09:04:23 +01:00
waldo
ff85bcf73b Fixed some linkes (I hope) 2021-11-11 09:03:15 +01:00
Jeremy Vyska
59b6931408
Merge pull request #17 from microsoft/jeremy-siteops
Update to Repo name
2021-11-11 08:52:43 +01:00
Jeremy Vyska
6c4cbf2f42
Merge pull request #16 from microsoft/waldo/prettifications
Just some minor changes
2021-11-11 08:52:33 +01:00
Jeremy Vyska
b56799e5d4
Update to Repo name 2021-11-11 08:50:21 +01:00
waldo
464c104632 Just some minor changes 2021-11-11 01:42:40 +01:00
waldo
6abfac51f7
Merge pull request #15 from microsoft/waldo/prettifications
Waldo/prettifications
2021-11-11 00:32:37 +01:00
waldo
f4832ae49f First draft for Guideline template 2021-11-10 15:55:39 +01:00
waldo
c5b0683f03 First draft for a template for Patterns 2021-11-10 15:38:31 +01:00
waldo
90e81f7713 Added info on homepage 2021-11-10 14:19:51 +01:00
Jeremy Vyska
6771da7dc8
Merge pull request #12 from microsoft/jeremy-siteops
Case sensitive issue
2021-11-10 10:19:14 +01:00
Jeremy Vyska
c8f7e2db11 Case sensitive issue 2021-11-10 10:18:49 +01:00
Jeremy Vyska
2d3e5d02a2
Merge pull request #11 from microsoft/jeremy-siteops
Renaming & Contrib Restructure
2021-11-10 10:16:46 +01:00
Jeremy Vyska
cc36c1b40c Updating main page, adding Contrib section 2021-11-10 10:15:55 +01:00
Jeremy Vyska
ffebb30b89 Finish client side rename, waiting on repo rename 2021-11-10 10:01:43 +01:00
Arend-Jan Kauffmann
79e3d31b4d Change CNAME 2021-11-10 08:45:40 +01:00
Jeremy Vyska
db1da7795e
Merge pull request #2 from JeremyVyska/main
Adding necessary file to keep Custom Domain
2021-11-09 14:19:32 +01:00
Jeremy Vyska
9ae88ce64a
Adding necessary file to keep Custom Domain 2021-11-09 14:02:26 +01:00
Jesper Schulz-Wedde
81ffc9da10
Merge pull request #1 from microsoft/waldo/prettifications
Prettifications
2021-11-08 16:52:49 +01:00
waldo
04944b1584 More prettifiations 2021-11-05 15:39:49 +01:00
waldo1001
7ff6ff73fa More prettifications 2021-11-05 13:52:12 +01:00
waldo1001
71e12a44a4 Prettified "Reusable Bugs" 2021-11-05 10:44:26 +01:00
waldo
7f33b0180f Changed "Eric Wauters" to his real name (just to try out the branching strategy) 2021-11-05 10:31:01 +01:00
Jeremy Vyska
6588f23109
Update site to use proper URL 2021-11-05 09:45:41 +01:00
Jeremy Vyska
a951e3a9ef
Updating Contributing Section 2021-11-05 08:47:59 +01:00
Jeremy Vyska
552e37fedc Merge branch 'main' of https://github.com/microsoft/bcalhelp 2021-11-04 22:35:10 +01:00
Jeremy Vyska
b300488e00 Updating URL to work in new repo (yay!) 2021-11-04 22:28:06 +01:00
Jeremy Vyska
d93e2b9166 Updating theme files 2021-11-04 22:23:55 +01:00
Jeremy Vyska
860c603457
Update README.md
Putting "Temporary" notice in since clever folks are finding it before Launch.  😃
2021-11-04 15:58:55 +01:00
Jeremy Vyska
85de82c28b
Fix to Edit link
Missed a trailing slash
2021-11-03 13:14:38 +01:00
Jeremy Vyska
26452d5f7c Formatting repair 2021-10-30 23:55:19 +02:00
Jeremy Vyska
89ac40c868 Merge branch 'main' of https://github.com/BC-Design-Patterns/AL-Dev-Help 2021-10-30 23:32:12 +02:00
Jeremy Vyska
8081662a64 Theme updates 2021-10-30 23:32:07 +02:00
Jeremy Vyska
adce7c8b5d Update of Landing Page 2021-10-30 23:31:41 +02:00
Jeremy Vyska
c3078b681e Fix name to fit better 2021-10-30 23:30:31 +02:00
Jeremy Vyska
aef549d3cd
Create LICENSE 2021-10-30 23:28:20 +02:00
Jeremy Vyska
4221d70d36 Just filling in some basics 2021-10-30 23:22:57 +02:00
Jeremy Vyska
bac7c0f879 Fixing up some titles 2021-10-30 23:04:37 +02:00
Jeremy Vyska
f4886ee235 Reorganizing 2021-10-30 22:09:32 +02:00
Jeremy Vyska
a4f6467d78 Enable quick jump to GH edit 2021-10-30 20:58:29 +02:00
Jeremy Vyska
72e338e2fe Lots of Title updating 2021-10-30 20:44:07 +02:00
Jeremy Vyska
aad74f9657 Home page, broken link fix. 2021-10-22 00:28:50 +02:00
Jeremy Vyska
6b32107a72 First pass conversion of NAV Patterns 2021-10-22 00:23:03 +02:00
Jeremy Vyska
1341938262 Basic config and skeleton of structure 2021-10-22 00:22:38 +02:00
Jeremy Vyska
17ee241708 Small start on site setup 2021-10-22 00:22:09 +02:00
Jeremy Vyska
f5fdb14ad8 Merge branch 'main' of https://github.com/BC-Design-Patterns/AL-Dev-Help 2021-10-21 20:09:15 +02:00
Jeremy Vyska
717823a86d Setting up Hugo and Theme 2021-10-21 20:09:10 +02:00
Jeremy Vyska
4f5b833e73
Create regen-gh-pages.yml 2021-10-21 20:05:36 +02:00
Jeremy Vyska
3180f9c6a2
Create README.md 2021-10-20 12:37:12 +02:00
500 changed files with 30281 additions and 8 deletions

27
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,27 @@
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04
# VARIANT can be either 'hugo' for the standard version or 'hugo_extended' for the extended version.
ARG VARIANT=hugo_extended
# VERSION can be either 'latest' or a specific version number
ARG VERSION=latest
# Download Hugo
RUN case ${VERSION} in \
latest) \
export VERSION=$(curl -s https://api.github.com/repos/gohugoio/hugo/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}') ;;\
esac && \
echo ${VERSION} && \
case $(uname -m) in \
aarch64) \
export ARCH=ARM64 ;; \
*) \
export ARCH=64bit ;; \
esac && \
echo ${ARCH} && \
wget -O ${VERSION}.tar.gz https://github.com/gohugoio/hugo/releases/download/v${VERSION}/${VARIANT}_${VERSION}_Linux-${ARCH}.tar.gz && \
tar xf ${VERSION}.tar.gz && \
mv hugo /usr/bin/hugo
# Hugo dev server port
EXPOSE 1313

View file

@ -0,0 +1,35 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.217.4/containers/hugo
{
"name": "Hugo",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"html.format.templating": true
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"bungcip.better-toml",
"davidanson.vscode-markdownlint",
"GitHub.vscode-pull-request-github"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
1313
],
"remoteUser": "vscode",
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": ""
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/go:1": {},
"ghcr.io/devcontainers/features/hugo:1": {},
"ghcr.io/devcontainers/features/node:1": {}
}
}

8
.gitattributes vendored Normal file
View file

@ -0,0 +1,8 @@
* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
*.gif binary
*.jpeg binary
*.png binary
*.gz binary
*.jar binary

73
.github/workflows/hugo.yml vendored Normal file
View file

@ -0,0 +1,73 @@
# Sample workflow for building and deploying a Hugo site to GitHub Pages
name: Deploy Hugo site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
# Default to bash
defaults:
run:
shell: bash
jobs:
# Build job
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.151.0
steps:
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Checkout
uses: actions/checkout@v3
- name: Setup Pages
id: pages
uses: actions/configure-pages@v3
- name: Install Node.js dependencies
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- name: Build with Hugo
env:
# For maximum backward compatibility with Hugo modules
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: |
hugo \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
public/
/node_modules/
/resources/_gen/
## Locking files for when working with local servers
.hugo_build.lock
package-lock.json

11
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start local Hugo server",
"type": "shell",
"command": "hugo serve",
"problemMatcher": []
}
]
}

23
CITATION.cff Normal file
View file

@ -0,0 +1,23 @@
cff-version: 1.2.0
title: ALGuidelines.dev
abstract: |
"Microsoft ALGuidelines - A Community driven project.
Best Practices and Design Patterns for the AL Language."
keywords:
- AL
- "Design Patterns"
- "Best Practices"
authors:
- given-names: Eric
family-names: Wauters
- given-names: Arend-Jan
family-names: Kauffmann
- given-names: Henrik
family-names: Helgesen
orcid: https://orcid.org/0000-0002-3281-6712
- given-names: Jeremy
family-names: Vyska
license: MIT
url: "https://alguidelines.dev"
repository-code: "https://github.com/microsoft/alguidelines"

View file

@ -1,15 +1,29 @@
# Project
# alguidelines.dev Site Source Repo
> This repo has been populated by an initial template to help get you started. Please
> make sure to update the content to build a great experience for community-building.
This is the source for the [alguidelines.dev](https://alguidelines.dev)
website.
# Business Central Design Patterns & Best Practices
As the maintainer of this project, please make a few updates:
This site is meant to house some of the community's knowledge about Microsoft Dynamics 365 Business Central AL Development best practices, particularly around hosting Design Patterns.
- Improving this README.MD file to provide a great experience
- Updating SUPPORT.MD with content about this project's support experience
- Understanding the security reporting process in SECURITY.MD
- Remove this section from the README
Please see the [ALGuidelines.dev](https://alguidelines.dev/) site for the full information about this project.
## Repo organization
This is a [hugo](https://gohugo.io) statically-generated site, hosted
on [GitHub Pages](https://https://pages.github.com). The site is automatically built by
GitHub Actions (see regen-gh-pages.yml).
All site content is stored in the `content` directory in markdown format.
```text
content/en
├── _index.html # Landing page
├── author # Info about blog authors
├── blog # Blog posts
├── docs # Documentation pages
└── search.md
```
## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
@ -24,6 +38,25 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
### Setup
**Run Hugo server**
```
$ hugo server
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
```
You can visit [localhost:1313](http://localhost:1313/) in browser to preview website.
### Making changes
1. Create a new branch
2. Make your changes
3. Verify your changes locally with Hugo server
4. Commit and push your changes to the branch
5. Raise a PR to main branch
6. Once PR is merged, your changes would be live on the site
## Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft

6
archetypes/default.md Normal file
View file

@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

BIN
assets/icons/SiteLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
assets/icons/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

1
assets/icons/logo.svg Normal file
View file

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 255 255"><defs><style>.cls-1{fill:#2ea98e;}</style></defs><title>AL logo_VS_smallest version_v3</title><path class="cls-1" d="M92.71,61.16a12.38,12.38,0,0,0-11.56-8h-.44a12.38,12.38,0,0,0-11.56,8l-52.79,138H46.58l8.06-23h52.58l8.06,23h30.21Zm-29.16,89,17.38-49.58L98.3,150.2Z"/><path class="cls-1" d="M189.7,172.2V54.2h-28V180.92c0,12.21,11.34,18.28,18,18.28h59v-27Z"/></svg>

After

Width:  |  Height:  |  Size: 461 B

218
assets/scss/_nav.scss Normal file
View file

@ -0,0 +1,218 @@
//
// Main navbar
//
.td-navbar-cover {
background: $primary;
@include media-breakpoint-up(md) {
background: transparent !important;
.nav-link {
text-shadow: 1px 1px 2px $dark;
}
}
&.navbar-bg-onscroll .nav-link {
text-shadow: none;
}
}
.navbar-bg-onscroll {
background: $primary !important;
opacity: inherit;
}
.td-navbar {
background: #212121;
min-height: 4rem;
margin: 0;
z-index: 32;
@include media-breakpoint-up(md) {
position: fixed;
top: 0;
width: 100%;
}
.navbar-brand {
text-transform: none;
text-align: middle;
.nav-link {
display: inline-block;
margin-right: -30px;
}
svg {
display: inline-block;
margin: 0 10px;
height: 30px;
}
}
.nav-link {
text-transform: none;
font-weight: $font-weight-bold;
}
.td-search-input {
border: none;
color: $navbar-dark-color;
@include placeholder {
color: $navbar-dark-color;
}
}
.dropdown {
min-width: 100px;
}
@include media-breakpoint-down(md) {
padding-right: .5rem;
padding-left: .75rem;
.td-navbar-nav-scroll {
max-width: 100%;
height: 2.5rem;
margin-top: .25rem;
overflow: hidden;
font-size: .875rem;
.nav-link {
padding-right: .25rem;
padding-left: 0;
}
.navbar-nav {
padding-bottom: 2rem;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
}
}
}
// Icons
#main_navbar {
li i {
padding-right: 0.5em;
&:before {
display: inline-block;
text-align: center;
min-width: 1em;
}
}
.alert {
background-color: inherit;
padding:0;
color: $secondary;
border: 0;
font-weight: inherit;
&:before {
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
font-family: "Font Awesome 5 Free";
font-weight: 900;
content: "\f0d9";
padding-left: 0.5em;
padding-right: 0.5em;
}
}
}
// Foldable sidebar menu
nav.foldable-nav {
&#td-section-nav {
position: relative;
}
&#td-section-nav label {
margin-bottom: 0;
width: 100%;
}
.td-sidebar-nav__section, .with-child ul {
list-style: none;
padding: 0;
margin: 0;
}
.ul-1 > li {
padding-left: 1.5em;
}
ul.foldable {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s cubic-bezier(0, 1, 0, 1);
}
input:checked ~ ul.foldable {
max-height: 100000vmax;
transition: max-height 1s ease-in-out;
}
input[type=checkbox] { display: none; }
.with-child, .without-child {
position: relative;
padding-left: 1.5em;
}
.ul-1 .with-child > label:before {
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
font-family: "Font Awesome 5 Free"; font-weight: 900; content: "\f0da";
position: absolute;
left: 0.1em;
padding-left: 0.4em;
padding-right: 0.4em;
font-size: 1em;
color: $gray-900;
transition: all 0.5s;
&:hover{
transform: rotate(90deg);
}
}
.ul-1 .with-child > input:checked ~ label:before {
color: $primary;
transform: rotate(90deg);
transition: transform 0.5s;
}
.with-child ul { margin-top: 0.1em; }
}
@media (hover: hover) and (pointer: fine) {
nav.foldable-nav {
.ul-1 .with-child > label:hover:before {
color: $primary;
transform: rotate(30deg);
transition: transform 0.5s;
}
.ul-1 .with-child > input:checked ~ label:hover:before {
color: $primary;
transform: rotate(60deg) !important;
transition: transform 0.5s;
}
}
}

View file

@ -0,0 +1,65 @@
//
// Right side toc
//
.td-sidebar-toc {
border-left: 1px solid $border-color;
@supports (position: sticky) {
position: sticky;
top: 4rem;
height: calc(100vh - 4rem);
overflow-y: auto;
}
order: 2;
padding-top: 0.75rem;
padding-bottom: 1.5rem;
vertical-align: top;
}
.td-page-meta {
a {
display: block;
font-weight: $font-weight-medium;
}
}
.td-toc {
padding-top: 5px;
margin-top: 10px;
border-top: 1px solid $black;
a {
display: block;
font-weight: $font-weight-medium;
padding-bottom: .25rem;
}
li {
list-style: none;
display: block;
}
li li {
margin-left: 0.5rem;
}
#TableOfContents {
// Hugo's ToC is a mouthful, this can be used to style the top level h2 entries.
> ul > li > ul > li > a {}
a {
color: $gray-600;
&:hover {
color: $blue;
text-decoration: none;
}
}
}
ul {
padding-left: 0;
}
}

View file

@ -0,0 +1,7 @@
.td-page-meta--child { display: none !important; }
.td-page-meta--project-issue { display: none !important; }
.td-content pre code {
font-family: Consolas, "Courier New", monospace;
size: 115%;
}

View file

@ -0,0 +1,728 @@
/*
Add styles or override variables from the theme here.
*/
@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700;900&display=swap');
body {
font-family: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif !important;
font-weight:500 !important;
}
$display1-weight: 500 !default;
$display2-weight: 100 !default;
$primary: #1f2a43 !default;
$primary-light: lighten($primary, 90%) !default;
$secondary: #2d70de !default;
$light: rgb(255, 255, 255) !default;
$grey: #888 !default;
$orange: $secondary;
ul, ol {
padding-left: 2em;
}
.navbar-logo {
height: 2em;
}
.nav-shadow {
box-shadow: 0 2px 2px -2px rgba(0,0,0,.2);
}
.navbar-brand {
color: #008489 !important
}
.navbar-bg-onscroll {
box-shadow: 0 2px 2px -2px rgba(0,0,0,.2);
#docsy-top {
display: block !important;
}
}
.control-bar {
display: none;
}
.td-content pre {
word-wrap: normal;
background-color: #f8f9fa;
padding: 1rem;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
}
.highlight > pre {
border: 0px;
}
.td-content blockquote {
border-radius: .15rem;
}
.notice.info {
border-left-color: #6bf;
background-color: rgba(102,187,255,.1);
}
.notice.warning {
border-left-color: #fd6;
background-color: rgba(255,221,102,.1);
}
.notice.danger {
border-left-color: #f66;
background-color: rgba(255,102,102,.1);
}
.notice > ul {
margin-bottom: 0em;
}
#docsy-search {
background: rgba(190, 185, 185, 0.3);
}
input[type="search"]::placeholder {
color: #9B9595 !important;
}
.td-box--secondary p > a:hover {
color: #121314 !important;
}
#community a {
color: #121314 !important;
}
.showcase img {
margin: 0 30px;
}
.td-content > h1 { font-weight: 700; }
.td-content > h2 { font-weight: 700; }
.td-content > h3 { font-weight: 700; }
.td-content > h4 { font-weight: 700; }
.td-content > h5 { font-weight: 700; }
.td-content > h6 { font-weight: 700; }
.td-content > h7 { font-weight: 700; }
// Custom CSS for homepage
.hero {
padding: 20px 0px 25px 0px;
color: white;
background: rgb(65, 127, 143);
background: linear-gradient(130deg, #4487a1 50%, #0188a3 70%);
margin-left: -15px;
margin-right: -15px;
position: relative;
overflow: hidden;
.container {
position: relative;
z-index: 2;
}
}
@media (min-width: 992px) {
.hero {
padding: 130px 0 100px;
}
.hero-banner {
transform: scale(1.4) translateY(10%);
}
}
@media (min-width: 1170px) {
.hero {
&:before {
content: '';
width: 60vw;
height: 60vw;
display: block;
background: linear-gradient(90deg, rgb(0, 129, 155) 59%, rgba(0,145,193,1) 70%);
position: absolute;
left: -20vw;
top: -20vw;
transform: rotate(45deg);
border-radius: 10%;
}
&:after {
content: '';
width: 20vw;
height: 100vw;
display: block;
background: linear-gradient(-74deg, #007e97 50%, #0091c1 70%);
position: absolute;
left: 55vw;
bottom: -40vw;
z-index: 1;
transform: rotate(45deg);
}
.container {
position: relative;
z-index: 2;
}
}
}
.hero-title {
font-family: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif !important;
font-weight: 700 !important;
// margin-top: 80px;
font-size: 56px;
}
// .hero-banner {
// margin-top: 80px;
// }
.hero-big {
background: rgb(0,145,193);
background: linear-gradient(
140deg,
rgba(0,145,193, 1) 0%,
rgba(0,94,113, 1) 100%
);
padding: 12px 38px;
border: none;
border-radius: 4px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 22px;
font-weight: 600;
color: white;
margin: 10px 0px 40px 0px;
}
.hero-mid {
background: rgb(0,145,193);
background: linear-gradient(140deg,rgba(0,145,193, 1) 0%, rgba(0,94,113, 1) 100%);
padding: 16px 30px;
border-radius: 4px;
border: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 18px;
font-weight: 600;
color: white;
margin: 30px 0px 10px 0px;
&:hover {
box-shadow: 0 3px 7px #b7b7b7;
}
}
.body-container {
margin-left: -15px;
margin-right: -15px;
}
.body-container .row {
padding: 30px 0px;
margin: 20px auto;
}
.td-navbar {
.nav-link {
font-weight: normal !important;
color: #f4f4f4 !important;
border-bottom: 1px solid transparent;
&:hover {
color: #fff !important;
border-bottom: 1px solid #00b1f7;
}
}
}
.td-search-input::placeholder {
color: #fff !important;
}
.section-title {
color: #3b3c4c;
font-weight: 700;
font-size: 46px;
margin: 12px 0px;
}
.section-text-bold {
color: #3b3c4c;
font-weight: 700;
margin: 12px 0px;
font-size: 18px;
line-height: 1.2;
}
.section-text {
color: #5a5b75;
font-weight: 600;
margin: 12px 0px;
font-size: 18px;
}
.wide-image {
// width: 100%;
margin-left: -15px;
margin-right: -15px;
}
.big-waves {
width: 100% !important;
position: relative;
top: -40px;
}
.push-up {
margin-top: -50px;
}
.center-text {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.push-up .col-lg-4, .whats-new .col-lg-4,
.community-cards .card-shadow, .community-cards.show-desktop .col-lg-6{
margin-bottom: 20px;
}
.card-shadow {
padding: 35px 30px 30px 30px;
text-align: center;
box-shadow: 0 5px 10px 0 rgba(41,26,204,0.12);
border: none;
border-radius: 6px;
height: 100%;
}
.card-shadow .section-text-bold {
font-size: 22px;
}
.card-shadow img {
margin: 2px auto;
}
.card-shadow .section-text {
color: #5a5b75;
font-size: 16px;
line-height: 1.5;
}
.feature-card {
padding: 20px;
border-radius: 0;
height: 100%;
border: 1px solid #E8E8E8;
background-color: #FFFFFF;
}
.feature-card .card-header-custom .section-text-bold {
font-size: 20px;
margin: 4px 0 0;
}
.feature-card p.section-text {
font-size: 15px;
}
.feature-card p:last-child {
margin-bottom: 0;
}
.card-header-custom {
display: flex;
flex-direction: row;
align-items: flex-start;
min-height: 58px;
}
.card-header-custom img {
margin-right: 16px;
}
.card-header-custom .section-text-bold {
font-size: 18px;
color: #3b3c4c;
}
.card .section-text {
font-size: 14px;
color: #5a5b75;
}
.info-card {
text-align: center;
margin: 0px auto 30px auto;
}
.info-card .section-text-bold {
font-size: 22px;
}
.info-card .section-text {
font-size: 17px;
}
.info-card img {
margin: 10px auto;
}
.whats-new {
background: url("/images/whats-new-bg.webp") no-repeat;
background-size: cover;
background-position: 0 -150px;
}
.whats-new .card-shadow {
height: 100%;
}
.whats-new .section-title {
color: white;
margin-bottom: 5px;
margin-top: 4rem
}
.whats-new .card-shadow {
background: white;
padding: 25px 15px 15px 15px;
min-height: unset;
box-shadow: 0 5px 10px 0 rgba(41,26,204,0.12);
}
.whats-new .card-shadow:hover {
box-shadow: 5px 10px 30px 0 rgba(41,26,204,0.12);
}
.whats-new .card-shadow-content {
padding: 0px 12px;
}
.whats-new .card-shadow button {
padding: 12px 22px !important;
}
@media (min-width: 992px) {
.whats-new .card-shadow .section-text-bold {
min-height: 80px;
}
.whats-new .card-shadow .section-text {
min-height: 122px;
}
}
.card-badge {
background: #f2f0fb;
padding: 6px 15px;
text-transform: uppercase;
border-radius: 5px;
color: #5a5b75;
font-weight: 600;
font-size: 16px;
}
.card-shadow .hero-mid {
width: 100%;
position: relative;
bottom: 0px;
}
.card-shadow .hero-mid-2 {
width: 100%;
position: relative;
bottom: 0px;
}
.hero-mid-2 {
background: white;
padding: 12px 22px;
border-radius: 4px;
border: 1px solid #00b1f7;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 18px;
font-weight: 600;
color: #00b1f7;
margin: 30px 0px 10px 0px;
font-weight: 700;
&:hover {
background: #55d7ff;
background: linear-gradient(140deg, #55d7ff 0%, #3d98b4 100%);
color: #fff;
box-shadow: 0 3px 7px #b7b7b7;
}
}
.community-cards {
background: url("/images/color-bg.webp") no-repeat center;
background-size: contain;
}
.community-cards .card-shadow {
background: white;
min-height: 150px;
padding: 16px 22px;
}
.community-cards .card-header-custom {
margin-right: auto;
display: flex;
align-items: center;
}
.community-cards .card-header-custom p.section-text-bold {
margin: 0;
}
.community-cards .card-shadow img {
margin-left: unset;
}
.community-cards .card-shadow .section-text {
text-align: left;
font-size: 14px;
margin-top: 4px;
}
.community-cards a:hover .card-shadow {
box-shadow: 0 10px 11px rgba(41, 26, 204, .12);
}
.text-highlight {
color: #00b1f7;
}
.community-cards .row {
padding: 30px 0px;
margin: 20px 2px;
}
.twitter-card-desktop {
position: relative;
left: 150px;
top: 10px;
}
.show-mobile {
display: none;
}
.show-mobile-inline {
display: none;
}
@media (max-width: 1299px) {
.hero {
background: url("/images/hero-bg.webp") no-repeat;
background-size: cover;
}
}
@media (max-width: 575px) {
.row {
display: inherit;
}
}
@media (min-width: 320px) and (max-width: 990px) {
.show-desktop {
display: none;
}
.show-mobile {
display: block;
}
.show-mobile-inline {
display: inline;
}
.hero {
background: url("/images/hero-bg.webp") no-repeat;
background-size: cover;
}
.hero-section-mobile .hero-title {
font-size: 39px;
}
.show-mobile-margin {
margin-top: 30px;
}
.card {
min-height: unset;
padding-bottom: 25px;
}
.card-shadow {
min-height: unset;
padding-bottom: 25px;
}
.whats-new {
background: url("/images/whats-new-bg.webp") no-repeat;
background-size: cover;
}
.community-cards {
background: unset;
}
}
.feature-section .card {
margin-bottom: 26px;
}
.feature-section .col-lg-4{
margin-bottom: 25px;
}
@media (max-width: 480px) {
.body-container .row {
padding: 30px 8px;
}
.community-cards {
background: unset;
}
}
.show-mobile-big {
display: none;
}
@media (max-width: 767px) {
.show-mobile-big {
display: block;
}
.show-desktop-big {
display: none;
}
.hero-section-mobile {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
}
.hero-section-mobile .show-mobile-big {
margin-top: 10px;
}
// {{< tabs >}}
// from https://github.com/alex-shpak/hugo-book
.hidden {
display: none;
}
.book-tabs {
margin-top: 1rem;
margin-bottom: 1rem;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius:.15rem;
overflow: hidden;
display: flex;
flex-wrap: wrap;
label {
display: inline-block;
padding: 0.5rem 1rem;
border-bottom: 1px transparent;
cursor: pointer;
}
.book-tabs-content {
order: 999;
width: 100%;
border-top: 1px solid #f8f9fa;
padding: 1rem;
display: none;
}
input[type="radio"]:checked + label {
border-bottom: 2px solid #05b;
}
input[type="radio"]:checked + label + .book-tabs-content {
display: block;
}
.book-tabs-content > .highlight {
margin: 0;
}
.book-tabs-content > blockquote.notice {
padding: 1.2em 0em 1.2em 1em;
margin-bottom: 1rem;
color: #616161;
border-left: 6px solid #2D70DE;
}
.book-tabs-content > blockquote.notice.notice.info { border-left-color: #6bf; }
.book-tabs-content > blockquote.notice.notice.warning { border-left-color: #fd6; }
.book-tabs-content > blockquote.notice.notice.danger { border-left-color: #f66; }
}
a {
text-decoration: inherit;
}
.post-img {
display: block;
> p {
text-align: center;
font-style: italic;
}
}
.DocSearch-Hit-title mark {
padding: 0;
}
.DocSearch-Hit-icon svg {
vertical-align: top;
}
.DocSearch-Hits mark {
padding: 0;
}
.DocSearch-Hit-content-wrapper {
overflow-y: hidden;
}

250
content/_index.md Normal file
View file

@ -0,0 +1,250 @@
---
title: "ALGuidelines.dev"
linkTitle: "ALGuidelines.dev"
description: "Design Patterns and Guidelines for AL development for Microsoft Dynamics 365 Business Central"
images: ["images/og-image-fission.png"]
---
<div class="hero">
<div class="container">
<div class="row justify-content-center align-items-center">
<div class="col-xl-7 col-lg-6 col-md-6 hero-section-mobile">
<h1 class="hero-title">
Guidelines and Patterns<br />
for Development for<br />
Microsoft Dynamics 365 Business Central
</h1>
<img
class="img-fluid hero-banner show-mobile-big"
src="/images/brainstorming-team-meeting_38894532.png"
alt-text="Teamwork Graphic"
/>
<br />
<a href="https://www.youtube.com/watch?v=CWpaD9RUa6U"
><button class="hero-big">
<i class="fab fa-youtube"></i>&nbsp;&nbsp; Watch the Launch
</button></a
>
</div>
<div class="col-xl-5 col-lg-6 col-md-6 show-desktop-big">
<img
class="img-fluid hero-banner"
src="/images/brainstorming-team-meeting_38894532.png"
alt-text="Teamwork Graphic"
/>
</div>
</div>
</div>
</div>
<div class="body-container">
<div class="container">
<br />
<div class="row">
<div class="col-lg-5">
<h2 class="section-title">Design Patterns?</h2>
<p class="section-text-bold">
A "Design Pattern" is a software design template to solve common development needs.
</p>
<p class="section-text">
This site is community run and Microsoft endorsed.
</p>
<a href="/docs"
><button class="hero-mid">Learn More</button></a
>
</div>
<div class="col-lg-7">
<img
class="img-fluid show-mobile-margin"
src="/images/body-img-1.png"
alt-text="Design Patterns Banner"
/>
</div>
</div>
</div>
</div>
<div class="wide-image show-desktop">
<img src="/images/wave.webp" class="big-waves" />
</div>
<div class="body-container push-up">
<div class="container">
<div class="row">
<div class="col-lg-12 center-text" style="margin-bottom: 50px">
<h2 class="section-title">Benefits</h2>
</div>
<div class="col-lg-4">
<div class="card-shadow">
<h2 class="section-text-bold"><i class="fas fa-retweet"></i></h2>
<h4 class="section-text-bold">Repeatability</h4>
<p class="section-text">
By using consistent patterns and best practices, code is far more reusable across diverse projects.
</p>
</div>
</div>
<div class="col-lg-4">
<div class="card-shadow">
<h2><i class="fas fa-people-carry"></i></h2>
<h4 class="section-text-bold">Teamwork</h4>
<p class="section-text">
If all code uses design patterns and best practices, it's simpler for new team members to ensure
that code is correct, as well as making it easier to jump into a project.
</p>
</div>
</div>
<div class="col-lg-4">
<div class="card-shadow">
<h2><i class="fas fa-rocket"></i></h2>
<h4 class="section-text-bold">Performance</h4>
<p class="section-text">
Many design patterns and best practices are also heavily focused on ensuring compliance with
the latest performance recommendations to get the most out of every system.
</p>
</div>
</div>
</div>
</div>
</div>
<div class="wide-image show-desktop">
<img src="/images/wave.webp" class="big-waves" />
</div>
<div class="body-container whats-new">
<div class="container">
<div class="row">
<div class="col-lg-12 center-text" style="margin-bottom: 40px">
<h2 class="section-title">What's New</h2>
</div>
<div class="col-lg-4">
<div class="card-shadow">
<span class="card-badge">NEW</span>
<h4 class="section-text-bold mt-4">
Getting Started With Agentic Coding
</h4>
<div class="card-shadow-content">
<p class="section-text">
Essential concepts and practices for working with AI coding assistants in your AL development workflow.
</p>
<a href="/docs/agentic-coding/gettingstarted/">
<button class="hero-mid-2 align-self-end">Get Started</button>
</a>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card-shadow">
<span class="card-badge">GUIDE</span>
<h4 class="section-text-bold mt-4">
Vibe Coding Rules
</h4>
<div class="card-shadow-content">
<p class="section-text">
AI-optimized coding rules and guidelines designed to enhance the AL developer experience in modern AI-powered IDEs.
</p>
<a href="/docs/agentic-coding/vibe-coding-rules/"
><button class="hero-mid-2 align-self-end">Explore Rules</button></a
>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card-shadow">
<span class="card-badge">TOOLS</span>
<h4 class="section-text-bold mt-4">
Agentic Tools
</h4>
<div class="card-shadow-content">
<p class="section-text">
Model Context Protocol (MCP) servers that enhance AI assistants for Business Central development workflows.
</p>
<a
href="/docs/agentic-coding/communityresources/tools/"
><button class="hero-mid-2 align-self-end">Explore Tools</button></a
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="body-container">
<div class="container">
<div class="row">
<div class="col-lg-4">
<br />
<br />
<h1 class="section-title">Join the Community</h1>
<br />
<div class="show-mobile">
<div class="community-cards">
<a href="https://discord.gg/4wbfNv3">
<div class="card-shadow">
<div class="card-header-custom">
<h2 style="padding-right: 0.8rem;"><i class="fab fa-discord"></i></h2>
<h2 class="section-text-bold">Discord</h2>
</div>
<p class="section-text">
Join the BC Community to engage with other BC Professionals.
</p>
</div>
</a>
<a href="https://github.com/microsoft/alguidelines">
<div class="card-shadow">
<div class="card-header-custom">
<h2 style="padding-right: 0.8rem;"><i class="fab fa-github"></i></h2>
<h2 class="section-text-bold">GitHub</h2>
</div>
<p class="section-text">
Dive into the code. Submit PRs
and collaborate with other like-minded contributors.
</p>
</div>
</a>
</div>
</div>
</div>
<div class="col-lg-8 community-cards show-desktop">
<div class="row">
<div class="col-lg-6">
<a href="https://discord.gg/4wbfNv3"
><div class="card-shadow">
<div class="card-header-custom">
<h2 style="padding-right: 0.8rem;"><i class="fab fa-discord"></i></h2>
<h2 class="section-text-bold">Discord</h2>
</div>
<p class="section-text">
Join the BC Community to engage with other BC Professionals.
</p>
</div></a
>
</div>
<div class="col-lg-6">
<a href="https://github.com/microsoft/alguidelines"
><div class="card-shadow">
<div class="card-header-custom">
<h2 style="padding-right: 0.8rem;"><i class="fab fa-github"></i></h2>
<h2 class="section-text-bold">GitHub</h2>
</div>
<p class="section-text">
Dive into the code. Submit PRs
and collaborate with other like-minded contributors.
</p>
</div></a
>
</div>
</div>
</div>
</div>
</div>
</div>

5
content/blog/_index.md Normal file
View file

@ -0,0 +1,5 @@
---
title: "AL Guidelines Blog"
linkTitle: "Blog"
type: "blog"
---

View file

@ -0,0 +1,96 @@
---
title: "Custom Telemetry"
tags: ["AL","Telemetry"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by Arend-Jan Kauffmann_
## Description
With AL it is possible to emit custom telemetry signals to Azure Application Insights. There are a number of considerations that you should keep in mind when designing custom telemetry signals.
- Think about it as an API
- Naming conventions and telemetry schema
- Objects emitting telemetry signals
- Candidate data for telemetry
- How customers use telemetry
- Privacy
## Think about it as an API
Customers will build analytics and monitoring solutions on top of their telemetry data.
Therefore, signal must be treated as any other API
- documented
- versioned
- discoverable
- non-breaking
## Naming conventions and telemetry schema
To make it easy for the consumer of telemetry to work with the data, please
- use **PascalCasing**. This makes all fields in Application Insights look the same (signal logged through the AL LogMessage method will have "al" prefixed to dimension names.
- **Do not use special characters or spaces** for fields/custom dimension keys. This makes the KQL queries so much easier to write
- for custom dimensions, consider using prefixes that helps the telemetry consumer understand where the dimension is coming from (e.g. HttpStatusCode, SqlStatement, ...)
Consider always having a **"message"** field that expresses in human readable form what the telemetry event is about.
If you do, let message names follow the Object ActionInPastTense pattern
Some examples
- Web Service Called:
- Email attempt failed
- Authorization to environment succeeded
```al
local procedure ProcessHttpResponse(var Request: HttpRequestMessage; var Response: HttpResponseMessage)
var
CustomTelemetryDimensions: Dictionary of [Text,Text];
begin
if Response.HttpStatusCode <> 200 then begin
CustomTelemetryDimensions.Add('Url', Request.GetRequestUri);
CustomTelemetryDimensions.Add('HttpStatusCode', Format(Response.HttpStatusCode));
CustomTelemetryDimensions.Add('ReasonPhrase', Response.ReasonPhrase);
Session.LogMessage(
'MyExt0001',
'Web service call failed',
Verbosity::Error,
DataClassification::SystemMetadata,
TelemetryScope::ExtensionPublisher,
CustomTelemetryDimensions);
end;
end;
```
## Objects emitting telemetry signals
Telemetry data includes information about the object that emitted the telemetry signal. It's recommended to call Session.LogMessage() **from within the object** that causes a situation that you want to have telemetry for. That will make it easier to analyze where exactly in the code an issue occurred.
Of course it is possible to have a single object as a central place to emit telemetry signals. The telemetry data includes a callstack, so eventually it would be possible to trace back to the exact place where an issue occurred. But that requires a more complicated query, so it would be better to emit telemetry signals right from place in the code where an issue occurred.
## Candidate data for telemetry
Telemetry must be **actionable** for the customer. Do not emit signals that they cannot act on (knowing about CPU performance counters on the database is useless if the partner cannot scale the database).
Also, note that customers pay for data ingestion. So be mindful to not flood their telemetry resources. Consider to use TelemetryScope::ExtensionPublisher by default and only use TelemetryScope::All in case the customer can also act on the data.
If you do not know where to start, consider using telemetry for deflection. In Dynamics 365 Business Central, they started with signal about authorization (successful/failed) to deflect support cases that was due to disabled users/wrong licenses.
## How customers use telemetry
The following are known scenarios for customer telemetry
- The tenant admin (typically an IT-pro) wants to troubleshoot a performance problem and they need more details than what is provided in the analytics reports in the admin center.
- The customer wants to analyze (and correct) errors happening in the environment (typically an IT-pro)
- The customer wants to analyze usage of features (typically an analytics user, maybe with BI experience)
Customers typically start in the Application Insights portal and then move on to use more advanced tools for analytics (KQL, Power BI, Excel, ...). Once they have seen the light, they will likely start alerting on telemetry using Azure Monitor Alerts or setting up Power Automate flows.
Business Central have developed a telemetry maturity model (based on the Gartner BI maturity model) for how organizations can evolve to use telemetry proactively in their business processes.
## Privacy
Telemetry must be **privacy compliant**.
For privacy reasons, events that have a DataClassification other than SystemMetadata aren't sent to Application Insight resources set up on the tenant. During development of your extension, it's good practice to have a privacy review of the use of LOGMESSAGE calls to ensure that customer data isn't mistakenly leaked into Application Insights resources.

View file

@ -0,0 +1,27 @@
---
title: "DeleteAll"
tags: ["AL","Performance"]
categories: ["Best Practice"]
---
_Created by waldo, Described by waldo_
## Description
When you perform a "DeleteAll" when there is nothing to delete, it will still perform a lock. When you for example perform a DeleteAll on an empty table, it will result in a table lock.
Therefore it's good practice to always check if the table is empty when performing a DeleteAll.
## Bad code
```al
EmptyTableWLD.SetRange(Code, 'AJ');
EmptyTableWLD.DeleteAll(true);
```
## Good code
```al
EmptyTableWLD.SetRange(Code, 'AJ');
if not EmptyTableWLD.IsEmpty() then
EmptyTableWLD.DeleteAll(true);
```

View file

@ -0,0 +1,69 @@
---
title: "SetLoadFields"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
See the documentation on learn.microsoft.com for more information about [SetLoadFields](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/methods-auto/record/record-setloadfields-method).
For the performance of your code it is important that you use SetLoadFields as much as possible.
If you want to retrieve a record from the database to check if the record is available always use SetLoadFields on the primary key fields of the table so only those fields will be retrieved from the database.
## Bad code
```AL
if not Item.Get(ItemNo) then
exit();
```
## Good code
```AL
Item.SetLoadFields("No.");
if not Item.Get(ItemNo) then
exit();
```
Place the SetLoadFields in the code before the line of the Get (or find). (there is no need to record filter fields in the SetLoadFields because these will be retrieved automatically).
## Bad code
```AL
Item.SetLoadFields("Item Category Code");
Item.SetRange("Third Party Item Exists", false);
Item.FindFirst();
```
## Good code
```AL
Item.SetRange("Third Party Item Exists", false);
Item.SetLoadFields("Item Category Code");
Item.FindFirst();
```
Place the SetLoadFields in the code before the case statement
## Bad code
```AL
Item.SetLoadFields("Item Category Code");
ItemCategoryCode := FindItemCategoryCode;
case true of
Item.Get(ItemNo):
SetItemCategoryCode(Item, ItemCategoryCode);
end;
```
## Good code
```AL
ItemCategoryCode := FindItemCategoryCode;
Item.SetLoadFields("Item Category Code");
case true of
Item.Get(ItemNo):
SetItemCategoryCode(Item, ItemCategoryCode);
end;
```

View file

@ -0,0 +1,201 @@
---
title: "Subscriber Codeunits"
tags: ["AL","Performance"]
categories: ["Best Practice"]
---
_Created by waldo, Described by waldo_
## Description
In general, subscribers have to be put in codeunits. There are a few performance considerations that you should keep in the back of your minds, when designing such a codeunit.
- Keep the codeunit as small as possible
- Work with a single instance codeunit
- only subscribe when necessary
- Avoid generic OnInsert/OnModify/OnDelete
Let's discuss all points
## Keep the codeunit as small as possible
Every time a subscriber gets called, a new instance of the codeunit is being loaded in memory, which takes memory and processing power. The smaller the codeunit, the less memory, and the faster it is.
Therefore, it's suggested to split the subscribers by functionality and avoid putting business logic in the actual codeunit. Tip: put all business logic in an "[Method Codeunit](https://alguidelines.dev/docs/patterns/generic-method-pattern/)".
Examples:
- if you app does things on Sales and Purchase, create a Sales-subs codeunit, and a Purchase-subs.
- if you have multiple functionalities in your app (let's call'm modules), create a subs-codeunit per module, and only add the subscribers in there that are necessary for that module.
### Bad code
```AL
codeunit 2037325 "Setup Subs"
{
SingleInstance = true;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Manual Setup", 'OnRegisterManualSetup', '', false, false)]
local procedure OnRegisterManualSetup(sender: Codeunit "Manual Setup")
var
AppId: ModuleInfo;
NameListLbl: Label 'Linked Texts Framework - List', Locked = true;
DescriptionListLbl: Label 'Edit linked texts', Locked = true;
KeyWordListLbl: Label 'LT,Distri,Technical,Functional,Reports', Locked = true;
NameReportLbl: Label 'Linked Texts Framework - Reports', Locked = true;
DescriptionReportLbl: Label 'View linked texts reports', Locked = true;
KeyWordReportLbl: Label 'LT,Distri,Technical,Functional,Reports', Locked = true;
begin
navapp.GetCurrentModuleInfo(AppId);
Sender.Insert(NameListLbl, DescriptionListLbl, KeyWordListLbl, page::"LTE Linked Text List", AppId.Id(), "Manual Setup Category"::General);
Sender.Insert(NameReportLbl, DescriptionReportLbl, KeyWordReportLbl, page::"LTE Linked Texts Reports", AppId.Id(), "Manual Setup Category"::General);
end;
[EventSubscriber(ObjectType::Codeunit, codeunit::"Manual Setup", 'OnRegisterManualSetup', '', false, false)]
local procedure OnRegisterManualSetup(sender: Codeunit "Manual Setup")
var
AppId: ModuleInfo;
NameLayoutLbl: Label 'Report Helper - Layout', Locked = true;
DescriptionLayoutLbl: Label 'Set up or update report layout list', Locked = true;
KeyWordLayoutLbl: Label 'RH,Distri,Technical,Functional,Reports,Layout', Locked = true;
NameCaptionsLbl: Label 'Report Helper - Captions', Locked = true;
DescriptionCaptionsLbl: Label 'Set up or update captions list', Locked = true;
KeyWordCaptionsLbl: Label 'RH,Distri,Technical,Functional,Reports,Captions', Locked = true;
NameFunctionsLbl: Label 'Report Helper - Functions', Locked = true;
DescriptionFunctionsLbl: Label 'Set up or disable functions', Locked = true;
KeyWordFunctionsLbl: Label 'RH,Distri,Technical,Functional,Reports,Functions', Locked = true;
NameDFCLbl: Label 'Report Helper - Default Footer', Locked = true;
DescriptionDFCLbl: Label 'Set up or update default footer', Locked = true;
KeyWordDFCLbl: Label 'RH,Distri,Technical,Functional,Reports,Default,Footer', Locked = true;
begin
navapp.GetCurrentModuleInfo(AppId);
Sender.Insert(NameLayoutLbl, DescriptionLayoutLbl, KeyWordLayoutLbl, page::"RHE Report Layout List", AppId.Id(), "Manual Setup Category"::General);
Sender.Insert(NameCaptionsLbl, DescriptionCaptionsLbl, KeyWordCaptionsLbl, page::"RHE Captions", AppId.Id(), "Manual Setup Category"::General);
Sender.Insert(NameFunctionsLbl, DescriptionFunctionsLbl, KeyWordFunctionsLbl, page::"RHE Functions", AppId.Id(), "Manual Setup Category"::General);
Sender.Insert(NameDFCLbl, DescriptionDFCLbl, KeyWordDFCLbl, page::"RHE Default Footer Card", AppId.Id(), "Manual Setup Category"::General);
end;
}
```
### Good code
Split into 2 codeunits, and move the business logic out.
```AL
codeunit 2037325 "LTE Setup Subs"
{
SingleInstance = true;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Manual Setup", 'OnRegisterManualSetup', '', false, false)]
local procedure OnRegisterManualSetup(sender: Codeunit "Manual Setup")
var
RegisterLTEManualSetup: codeunit "Register LTE Manual Setup";
begin
RegisterLTEManualSetup.RegisterLTEManualSetup();
end;
}
codeunit 2037324 "RHE Setup Subs"
{
SingleInstance = true;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Manual Setup", 'OnRegisterManualSetup', '', false, false)]
local procedure OnRegisterManualSetup(sender: Codeunit "Manual Setup")
var
RegisterRHEManualSetup: codeunit "Register RHE Manual Setup";
begin
RegisterRHEManualSetup.RegisterRHEManualSetup();
end;
}
```
## Work with a single instance codeunit
To avoid the extra "loading of the content" while a subscriber is being executed, use Single Instance codeunit for subscribers. Do take into account, of course, that it would share the state across the entire session.
### Bad code
```AL
codeunit 2037324 "RHE Setup Subs"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Manual Setup", 'OnRegisterManualSetup', '', false, false)]
local procedure OnRegisterManualSetup(sender: Codeunit "Manual Setup")
var
RegisterRHEManualSetup: codeunit "Register RHE Manual Setup";
begin
RegisterRHEManualSetup.RegisterRHEManualSetup();
end;
}
```
### Good code
```AL
codeunit 2037324 "RHE Setup Subs"
{
SingleInstance = true;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Manual Setup", 'OnRegisterManualSetup', '', false, false)]
local procedure OnRegisterManualSetup(sender: Codeunit "Manual Setup")
var
RegisterRHEManualSetup: codeunit "Register RHE Manual Setup";
begin
RegisterRHEManualSetup.RegisterRHEManualSetup();
end;
}
```
## only subscribe when necessary
If possible, only execute the subscriber when really necessary by using Manual Binding.
### Bad code
```AL
//subscriber - code should actually only run when Color=Red.
[EventSubscriber(ObjectType::Table, Database::"Just Some Table WLD", 'OnAfterValidateEvent', 'Message 2', false, false)]
local procedure JustDoSomthing(var Rec: Record "Just Some Table WLD"; var xRec: Record "Just Some Table WLD")
begin
if Rec.color <> 'RED' then
exit; //only execute when necessary
...
end;
//business logic
if JustSomeTable.FindSet() then
repeat
JustSomeTable.Validate("Message 2", format(Random(1000)));
until JustSomeTable.Next() < 1;
```
### Good code
```AL
if JustSomeTable.FindSet() then
repeat
if JustSomeTable.Color = 'RED' then
BindSubscription(DemoSubs);
JustSomeTable.Validate("Message 2", format(Random(1000)));
if JustSomeTable.Color = 'RED' then
UnbindSubscription(DemoSubs);
until JustSomeTable.Next() < 1;
```
## Avoid OnInsert/OnModify/OnDelete
The reason for this is, that it breaks the batch-calls:
- Any "OnInsert" subscriber breaks the bulk inserts, simply because it needs to perform an operation after every record that was inserted
- Any "OnModify" subscriber slows down the "ModifyAll", simply because it needs to perform an operation after every record that was modified. I fact: 1 SQL call is turned into a loop of SQL calls.
- Any "OnDelete" subscriber slows down the "DeleteAll", simply because it needs to perform an operation after every record that was deleted. I fact: 1 SQL call is turned into a loop of SQL calls.
Avoid subscribers to these events.
## References
The [Generic Method Pattern](https://alguidelines.dev/docs/patterns/generic-method-pattern/)

View file

@ -0,0 +1,24 @@
---
title: "Best Practices"
weight: 3
description: >
AL Code Best Practices
---
This section will be cover things that aren't as simple as Design Patterns, but will help make sure your development is:
- high-performance
- complies with good designs
- has high maintainability
## Readability
Generally, all readability rules are Microsoft style choices only. You can use them to keep consistency with the existing code.
## Performance
Some guidelines are simply better for performance considerations rather than readability or anything else. In this section, let's look into some..
## Discussion
All discussion related to Best Practice are to be found on the Github Repo's Discussion pages, found [here](https://github.com/microsoft/alguidelines/discussions/categories/bc-best-practices)

View file

@ -0,0 +1,187 @@
---
title: "API Page / Query"
tags: ["AL","API"]
categories: ["Best Practice"]
---
_Created by Arend-Jan Kauffmann, Described by Arend-Jan Kauffmann_
## Description
API pages are different from UI pages. They require different properties and don't behave the same. Because API pages are used for integration with external applications, they should be treated as contracts. To achieve this, the following topics are important.
- Separate API app
- Page properties
- Versioning
- Field properties
- Default fields
## Separate API app
It's a good practice to develop API pages in a separate app instead of combining them in a solution. By doing so, it provides better maintainability and is a good way of separation of concerns.
## Page properties
An API page must define a minimum set of properties. Some of these properties will be part of the URL of the API endpoint. It is recommended to define the properties in the same order as they appear in the URL.
The properties that must be defined are:
- PageType = API / QueryType = API
- APIPublisher
- APIGroup
- APIVersion
- EntitySetName
- EntityName
- DelayedInsert (only Page)
- ODataKeyFields
### APIPublisher
The name of the API publisher is usually the company creating the API. It is the first custom part in the URL for a given endpoint. While the value is case insensitive for HTTP operations (GET, POST, etc.), it is case sensitive when checking for active subscriptions.
Example:
```al
APIPublisher = 'contoso';
```
### APIGroup
Sets the group of the API endpoint that page or query is exposed in. In the URL the APIGroup comes after the APIPublisher. It can be used to distinguish different API apps or groups of APIs from each other. While the value is case insensitive for HTTP operations (GET, POST, etc.), it is case sensitive when checking for active subscriptions.
Example:
```al
APIGroup = 'app1';
```
### APIVersion
Sets the version(s) of the API endpoint the page or query is exposed in. This property is not mandatory. If it is not specified, then APIs will be exposed as version 'beta'.
The APIVersion can be set to 'beta' or have the format 'vx.y'.
Example:
```al
APIVersion = 'beta';
```
or
```al
APIVersion = 'v1.0';
```
#### _Multiple API versions_
You should __never__ break existing versions. Any breaking change requires to create a new version.
It is possible to expose an API in multiple versions:
```al
APIVersion = 'beta', 'v1.0';
```
This allows to publish a new version of an API app without copying all individual objects and updating the version numbers. Only those API objects that are changed in a new version need to be copied. The other objects only need an addition to the APIVersion property to become available in the new version endpoint.
### EntitySetName
The EntitySetName is the plural entity name. Think of it as the name of the collection of entities. It is recommended to use camelCasing for this property. The value is case sensitive!
Example:
```al
EntitySetName = 'itemCategories';
```
### EntityName
The EntityName sets the singular entity name for the API page or query. This name is not used in the URL. Instead, the EntityName is used in the metadata information. It is recommended to use camelCasing for this property.
Example:
```al
EntityName = 'itemCategory';
```
### DelayedInsert
This property is required on an editable API page. It does not apply to an API query object. If ```Editable = false``` is set on the API page, then DelayedInsert is not required.
All APIs pages apply the behavior to first specify all field values and then insert the record at once.
Example:
```al
DelayedInsert = true;
```
### Full example
Together, the page properties look like:
```al
PageType = API;
APIPublisher = 'contoso';
APIGroup = 'app1';
APIVersion = 'v1.0';
EntitySetName = 'itemCategories';
EntityName = 'itemCategory';
DelayedInsert = true;
```
The full url will look like: ```https://{url}/api/contoso/app1/v1.0/companies({id})/itemCategories```
### ODataKeyFields
The ```EntitySetName``` property in the URL can be extended with an identifier to indicate a single record.
Example:
```
.../itemCategories(768b6173-9b19-40ea-8e5d-ce181ec0d645)
```
The property ```ODataKeyFields``` defines which field(s) will be used for the identifier value. It is highly recommended to always use the SystemId field for this property. The SystemId field is immutable and will never change for a record.
The field that is defined in this property should be part of the API page.
## Field properties
The base structure of an API page is similar to a UI list page:
```al
layout
{
area(Content)
{
repeater(records)
{
...
}
}
}
```
When specifying the fields there are some considerations to keep in mind.
```
field(displayName; Rec.Name) { }
```
There are no mandatory properties. The property ```ApplicationArea``` does not play a role in API pages, so it can be skipped. The property ```Caption``` is also optional and should only be used in case the external application requires captions and the caption should be different from the standard caption as defined in the table.
The name of the field, in the example above ```displayName```, should be defined in camelCasing. It may not contain spaces, dots, or other special characters.
It is common use to give certain fields a more describing name. Some examples are:
* id for field SystemId
* number for field "No."
* displayName for field Name
## Mandatory fields
These fields should always be part of the API Page:
* SystemId
* This field should be exposed with the name ```id```
* SystemModifiedAt
* This field should be exposed with the name ```lastModifiedDateTime```. If you choose a different name, then the webhook functionality will not work properly.
Example:
```al
layout
{
area(Content)
{
repeater(records)
{
field(id; Rec.SystemId) { }
field(lastModifiedDateTime; Rec.SystemModifiedAt) { }
}
}
}
```

View file

@ -0,0 +1,28 @@
---
title: "begin as an afterword"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
When `begin` follows `then`, `else`, `do`, it should be on the same line, preceded by one space character.
## Bad code
```al
if ICPartnerRefType = ICPartnerRefType::"Common Item No." then
begin
...
end;
```
## Good code
```al
if ICPartnerRefType = ICPartnerRefType::"Common Item No." then begin
...
end;
```

View file

@ -0,0 +1,65 @@
---
title: "Begin-End - Compound Only"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
Only use begin..end to enclose [compound statements](https://docs.microsoft.com/en-us/cpp/c-language/compound-statement-c?view=msvc-170#:~:text=A%20compound%20statement%20%28also%20called%20a%20%22block%22%29%20typically,appear%20at%20the%20head%20of%20a%20compound%20statement.).
## Example 1
### Bad code
```AL
if FindSet() then begin
repeat
...
until next() = 0;
end;
```
### Good code
```AL
if FindSet() then
repeat
...
until next() = 0;
```
## Example 2
### Bad code
```AL
if IsAssemblyOutputLine then begin
TestField("Order Line No.", 0);
end;
```
### Good code
```AL
if IsAssemblyOutputLine then
TestField("Order Line No.", 0);
```
## Exception
```AL
// Except for this case
if X then begin
if Y then
//DO SOMETHING;
end else
(not X)
```
## Tips
The [AZ AL Dev Tools/AL Code Outline](https://marketplace.visualstudio.com/items?itemName=andrzejzwierzchowski.al-code-outline) extension adds two new commands to Visual Studio Code to remove begin..end around single statements.
- `Remove Begin..End around Single Statements from the Active Editor` : removes begin..end around single statement from the current editor
- `Remove Begin..End around Single Statements from the Active Project` : removes begin..end around single statement from the current project

View file

@ -0,0 +1,27 @@
---
title: "Binary Operator to Start Line"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
Do not start a line with a binary operator.
## Bad code
```AL
"Quantity to Ship" :=
Quantity
- "Quantity Shipped"
```
## Good code
```AL
"Quantity to Ship" :=
Quantity -
"Quantity Shipped"
```

View file

@ -0,0 +1,115 @@
---
title: "When not to use Blank Lines"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
## Description
Do not use blank lines:
- at the beginning or end of any functions (after `begin` and before `end`)
- inside multiline expression
- after blank lines
## Example 1
### Bad code
```al
procedure MATRIX_OnDrillDown(MATRIX_ColumnOrdinal: Integer)
begin
SetupDrillDownCol(MATRIX_ColumnOrdinal);
DrillDown(false, ValueType);
end;
```
### Good code
```al
procedure MATRIX_OnDrillDown(MATRIX_ColumnOrdinal: Integer)
begin
SetupDrillDownCol(MATRIX_ColumnOrdinal);
DrillDown(false, ValueType);
end;
```
## Example 2
### Bad code
```al
if NameIsValid and
Name2IsValid
then
```
### Good code
```al
if NameIsValid and
Name2IsValid
then
```
## Example 3
### Bad code
```al
var
GLSetup: Record "General Ledger Setup";
GLSetupRead: Boolean;
local procedure GetGLSetup()
begin
if not GLSetupRead then
GLSetup.Get();
GLSetupRead := true;
OnAfterGetGLSetup(GLSetup);
end;
[IntegrationEvent(false, false)]
local procedure OnAfterGetGLSetup(var GLSetup: Record "General Ledger Setup")
begin
end;
```
### Good code
```al
var
GLSetup: Record "General Ledger Setup";
GLSetupRead: Boolean;
local procedure GetGLSetup()
begin
if not GLSetupRead then
GLSetup.Get();
GLSetupRead := true;
OnAfterGetGLSetup(GLSetup);
end;
[IntegrationEvent(false, false)]
local procedure OnAfterGetGLSetup(var GLSetup: Record "General Ledger Setup")
begin
end;
```
## Tips
The [AZ AL Dev Tools/AL Code Outline](https://marketplace.visualstudio.com/items?itemName=andrzejzwierzchowski.al-code-outline) extension adds two new commands to Visual Studio Code to remove empty duplicate lines.
- `Remove Empty Lines from the Active Editor` : removes empty duplicate lines from the current editor
- `Remove Empty Lines from the Active Project` : removes empty duplicate lines from the current project

View file

@ -0,0 +1,31 @@
---
title: "CASE Action on next line"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
A CASE action should start on a line after the possibility.
## Bad code
```AL
case Letter of
'A': Letter2 := '10';
'B': Letter2 := '11';
end;
```
## Good code
```AL
case Letter of
'A':
Letter2 := '10';
'B':
Letter2 := '11';
end;
```

View file

@ -0,0 +1,23 @@
---
title: "Comment Spacing"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
Always start comments with // followed by one space character.
## Bad code
```al
RowNo += 1000; //Move way below the budget
```
## Good code
```al
RowNo += 1000; // Move way below the budget
```

View file

@ -0,0 +1,35 @@
---
title: "end else pair"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
The `end else` pair should always appear on the same line.
## Bad code
```al
if OppEntry.Find('-') then
if SalesCycleStage.Find('-') then begin
...
end
else
begin
...
end;
```
## Good code
```al
if OppEntry.Find('-') then
if SalesCycleStage.Find('-') then begin
...
end else begin
...
end;
```

View file

@ -0,0 +1,109 @@
---
title: "if not then exit"
tags: ["AL"]
categories: ["Best Practice"]
---
_Created by sirhc101, Described by sirhc101_
## Description
In general when we are working with tables we want to make sure, the filtered dataset includes records and does not result in a runtime error, so we use `if` to handle the result of `Find()`, `FindSet()`, `Get()`, etc.
This automatically causes on indent in source code and often the source code does not just contain one but two or more tables involved which leads to multi-level indentation.
Basically this is a result of bad coding structure but maybe sometimes necessary. On the other hand this causes multiple `end;` usages and leads to the usage of colorization and other helpers to see which `begin` belongs to which `end;`.
Instead of using `if (Record.FindSet()) then` to fetch records from a database it's good practice to use `if (not Record.FindSet()) then` following by an `exit();` to not further process the source code and make it clear for other developers where they can stop reading in certain cases.
Furthermore, this more or less automatically leads to smaller and better structured procedures and reduces the complexity of the source code.
## Bad code
```al
SalesHeader.Reset();
SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
SalesHeader.SetRange(Status, SalesHeader.Status::Open);
if (SalesHeader.FindSet(false)) then begin
repeat
SalesLine.Reset();
SalesLine.SetRange("Document Type", SalesHeader."Document Type"::Order);
SalesLine.SetRange("Document No.", SalesHeader."No.");
if (SalesLine.FindSet(true)) then begin
repeat
DoSomething();
until SalesLine.Next() = 0;
end;
until SalesHeader.Next() = 0;
DoSomethingElse();
end;
```
or
```al
SalesLine.Reset();
SalesLine.SetRange("Document Type", SalesHeader."Document Type"::Order);
if (SalesLine.FindSet(true)) then begin
repeat
case SalesLine."Type" of
SalesLine."Type"::Item:
DoSomethingItem();
SalesLine."Type"::Resource:
DoSomethingResource();
end;
until SalesLine.Next() = 0;
end;
```
## Good code
```al
procedure DoSomethingSalesOrder()
var
SalesHeader: Record "Sales Header";
begin
SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
SalesHeader.SetRange(Status, SalesHeader.Status::Open);
if (not SalesHeader.FindSet(false)) then
exit;
repeat
DoSomethingSalesLine(SalesHeader);
until SalesHeader.Next() = 0;
DoSomethingElse();
end;
procedure DoSomethingSalesLine(var SalesHeader: Record "Sales Header")
var
SalesLine: Record "Sales Line";
begin
SalesLine.Reset();
SalesLine.SetRange("Document Type", SalesHeader."Document Type"::Order);
SalesLine.SetRange("Document No.", SalesHeader."No.");
if (not SalesLine.FindSet(true)) then
exit;
repeat
DoSomething();
until SalesLine.Next() = 0;
end;
```
or
```al
SalesLine.SetRange("Document Type", SalesHeader."Document Type"::Order);
if (not SalesLine.FindSet(true)) then
exit;
repeat
case SalesLine."Type" of
SalesLine."Type"::Item:
DoSomethingItem();
SalesLine."Type"::Resource:
DoSomethingResource();
end;
until SalesLine.Next() = 0;
```

View file

@ -0,0 +1,60 @@
---
title: "IsTemporary record safeguard"
tags: ["AL"]
categories: ["Best Practice"]
---
_Created by Kine, Described by Kine_
## Description
When you are working with temporary tables or real tables, you can have code, where you assume that Record variable is or is not temporary. Best practice is to not assume, but test it to be sure. In history,
many developers went through painful period when they did unwanted "DeleteAll" over real table in production database, because they were only assuming something (mostly it happened only once to them).
Therefore it is good practice to use [Record.IsTemporary()](https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/methods-auto/record/record-istemporary-method) method to test this predicate, mainly when you are doing destructive action.
Another case when it is good practice to use this test is when you are subscribing to triggers on table. In most cases, you do not want to run your code when the trigger is running over temporary record. And you cannot assume, that
this specific table will not be used as temporary by someone else. Reacting to the trigger as if it was triggered by real table change could lead to corrupted data or unpredictable errors and the reason could be hard to find.
## Bad code
```al
ShouldBeTemporary.DeleteAll(true);
```
or
```al
[EventSubscriber(ObjectType::Table, Database::"Some Table", 'OnAfterInsertEvent', '', false, false)]
local procedure DoSomethingOnAfterInsertSomeTable(var Rec: Record "Some Table")
begin
DoSomething(Rec);
end;
```
## Good code
```al
if ShouldBeTemporary.IsTemporary() then
ShouldBeTemporary.DeleteAll(true);
```
or
```al
if not ShouldBeTemporary.IsTemporary() then
Error(RecNotTemporaryErr);
ShouldBeTemporary.DeleteAll(true);
```
or
```al
[EventSubscriber(ObjectType::Table, Database::"Some Table", 'OnAfterInsertEvent', '', false, false)]
local procedure DoSomethingOnAfterInsertSomeTable(var Rec: Record "Some Table")
begin
if Rec.IsTemporary() then
Exit;
DoSomething(Rec);
end;
```

View file

@ -0,0 +1,39 @@
---
title: "Keyboard Shortcuts"
tags: ["AL","Productivity"]
categories: ["Best Practice"]
---
_Created by Christian Lenz, Described by Christian Lenz_
## Description
To increase developer productivity while coding, use keyboard shortcuts that are available in the specific context to execute actions faster.
This is a selection of the community's favorites (more to come).
**Windows**
| What | Where | How |
|---|---|---|
| Delete word | Editor | CTRL + Backspace |
**VS Code**
| What | Where | How |
|---|---|---|
| Switch Tab | Editor | ALT + <Arrow Left/Right> |
| Move Line Up/Down | Editor | ALT + <Arrow Up/Down> |
| Copy Line Below/Above | Editor | ALT + SHIFT + <Arrow Up/Down> |
| Delete Line | Editor | CTRL + X (without selection) |
| Add Selection To Next Match | Editor | CTRL + D |
| Select All Occurences Of Find Match | Editor | CTRL + SHIFT + L |
| Add Cursors To Line Ends | Editor | SHIFT + ALT + I (after selecting lines) |
| Add Cursor Above/Below | Editor | CTRL + ALT + <Arrow Up/Down> |
| Place Multiple Cursors Manually | Editor | ALT + Click |
| Fast Scrolling | Editor | ALT + Mouse Wheel |
| Go To Symbol In File | Editor | CTRL + SHIFT + O |
| Breadcrumbs - Open And Select | Editor | CTRL + SHIFT + . |
| Go Back / Forward | Go To Definition | ALT + <Arrow Left/Right> |

View file

@ -0,0 +1,26 @@
---
title: "Keyword Pairs - Indentation"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
The `if..then` pair, `while..do` pair, and `for..do` pair must appear on the same line or the same level of indentation. If possible, you can align the lines it is even much more readable.
## Bad code
```al
if (x = y) and
(a = b) then
```
## Good code
```al
if (x = y) and
(a = b)
then
```

View file

@ -0,0 +1,31 @@
---
title: "Line Start Keywords"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
The `end`, `if`, `repeat`, `for`, `while`, `else` and `case` statement should always start a line.
## Bad code
```al
if IsContactName then ValidateContactName()
else if IsSalespersonCode then ValidateSalespersonCode()
else if IsSalesCycleCode then ValidatSalesCycleCode();
```
## Good code
```al
if IsContactName then
ValidateContactName()
else
if IsSalespersonCode then
ValidateSalespersonCode()
else
if IsSalesCycleCode then
ValidatSalesCycleCode();
```

View file

@ -0,0 +1,24 @@
---
title: "Lonely Repeat"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
The `repeat` statement should always be alone on a line.
## Bad code
```al
if ReservEntry.FindSet() then repeat
```
## Good code
```al
if ReservEntry.FindSet() then
repeat
```

View file

@ -0,0 +1,29 @@
---
title: "Named Invocations"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
When calling an object statically use the Object Name, not the Object Id.
## Bad code
```al
Page.RunModal(525, SalesShptLine);
```
## Good code
```al
Page.RunModal(Page::"Posted Sales Shipment Lines", SalesShptLine);
```
## Tips
The [BusinessCentral.LinterCop](https://marketplace.visualstudio.com/items?itemName=StefanMaron.businesscentral-lintercop) extension adds a new rule to check your code for hardcoded object IDs.
- [LC0012](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0012): Using hardcoded IDs in functions like Codeunit.Run() is not allowed.

View file

@ -0,0 +1,41 @@
---
title: "One Statement per Line"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
A line of code should not have more than one statement.
## Example 1
### Bad code
```al
if OppEntry.Find('-') then exit;
```
### Good code
```al
if OppEntry.Find('-') then
exit;
```
## Example 2
### Bad code
```al
TotalCost += Cost; TotalAmt += Amt;
```
### Good code
```al
TotalCost += Cost;
TotalAmt += Amt;
```

View file

@ -0,0 +1,29 @@
---
title: "Seperate if and else"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
`if` and `else` statements should be on separate lines.
## Bad code
```al
if Atom = '>' then HasLogicalOperator := true else begin
...
end;
```
## Good code
```al
if Atom = '>' then
HasLogicalOperator := true
else begin
...
end;
```

View file

@ -0,0 +1,53 @@
---
title: "Spacing Binary Operators"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
There must be exactly one space character on each side of a binary operator such as = + - AND OR =. The parameter comma operator however, should have a space after the comma.
## Example 1
### Bad code
```al
"Line Discount %" := "Line Discount Amount"/"Line Value"*100;
```
### Good code
```al
"Line Discount %" := "Line Discount Amount" / "Line Value" * 100;
```
## Example 2
### Bad code
```al
StartDate := CalcDate('<+'+Format(Days+i)+'D\>',StartDate);
```
### Good code
```al
StartDate := CalcDate('<+' + Format(Days + i) + 'D\>', StartDate);
```
## Example 3
### Bad code
```al
StartDate:=0D; // Initialize
```
### Good code
```al
StartDate := 0D; // Initialize
```

View file

@ -0,0 +1,361 @@
---
title: "Suggested Abbreviations"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
Whenever possible, do **not** use abbreviations in variables, functions and objects names.
If there is no other choice, then use the suggestions below.
| word | Abbreviation |
|---|---|
| absence | Abs |
| account | Acc |
| accounting | Acc |
| accumulated | Accum |
| action | Act |
| activity | Activ |
| additional | Add |
| address | Addr |
| adjust | Adj |
| adjusted | Adjd |
| adjustment | Adjmt |
| agreement | Agrmt |
| allocation | Alloc |
| allowance | Allow |
| alternative | Alt |
| amount | Amt |
| amounts | Amts |
| answer | Ans |
| applies | Appl |
| application | Appln |
| arrival | Arriv |
| assembly | Asm |
| assemble to order | ATO |
| assignment | Assgnt |
| associated | Assoc |
| attachment | Attmt |
| authorities | Auth |
| automatic | Auto |
| availability | Avail |
| average | Avg |
| ba db. | BA |
| balance | Bal |
| bill of materials | BOM |
| blanket | Blnkt |
| budget | Budg |
| buffer | Buf |
| business | Bus |
| business interaction management | BIM |
| buying | Buy |
| calculate | Calc |
| calculated | Calcd |
| calculation | Calcu |
| calendar | Cal |
| capacity | Cap |
| capacity requirements planning | CRP |
| cash flow | CF |
| cashflow | CF |
| catalog | ctlg |
| category | Cat |
| Central Processing Unit | CPU |
| center | Ctr |
| change | Chg |
| changes | Chgs |
| character | Char |
| characters | Chars |
| charge | Chrg |
| charges | Chrgs |
| check | Chk |
| classification | Class |
| collection | coll |
| column | col |
| comment | Cmt |
| company | Co |
| component | Comp |
| completion | Cmpltn |
| components | Comps |
| composition | Compn |
| compression | Compr |
| concurrent | Concrnt |
| confidential | Conf |
| confirmation | Cnfrmn |
| conflict | Confl |
| consolidate | Consol |
| consolidation | Consolid |
| consumption | Consump |
| contact | Cont |
| container | Cntr |
| contract | Contr |
| contracted | Contrd |
| control | Ctrl |
| controls | Ctrls |
| conversion | Conv |
| correction | Cor |
| correspondence | Corres |
| corresponding | Corresp |
| cost | Cst |
| sold | COGS |
| credit | Cr |
| cumulate | Cumul |
| currency | Curr |
| current | Crnt |
| customer | Cust |
| customer/vendor | CV |
| daily | Dly |
| dampener | Damp |
| database management system | DBMS |
| date | D |
| definition | Def |
| demonstration | Demo |
| department | Dept |
| department/project | DP |
| depreciation | Depr |
| description | Desc |
| detail | Dtl |
| detailed | Dtld |
| details | Dtls |
| deviation | Dev |
| difference | Diff |
| dimension | Dim |
| direct | Dir |
| discount | Disc |
| discrete | Discr |
| distribute | Distr |
| distributed | Distrd |
| distributor | Distbtr |
| distribution | Distrn |
| document | Doc |
| duplicate | Dupl |
| entered | Entrd |
| engineering | Engin |
| exchange | Exch |
| excluding | Excl |
| execute | Exec |
| expected | Expd |
| expedited | Exped |
| expense | Exp |
| expression | Expr |
| expiration | Expir |
| extended | Ext |
| explode | Expl |
| export | Expt |
| final | Fnl |
| finance | Fin |
| fiscal | Fisc |
| finished | Fnshd |
| fixed asset | FA |
| forward | Fwd |
| freight | Frt |
| general | Gen |
| general ledger | GL |
| group | Gr |
| header | Hdr |
| history | Hist |
| holiday | Hol |
| human resource | HR |
| identification | ID |
| import | Imp |
| inbound | Inbnd |
| including | Incl |
| included | Incld |
| incoming | Incmg |
| independent software vendor | ISV |
| industry | Indust |
| information | Info |
| initial | Init |
| Intrastat | Intra |
| interaction | Interact |
| integration | Integr |
| interest | Int |
| Interim | Intm |
| internal protocol | IP |
| inventory | Invt |
| inventoriable | Invtbl |
| invoice | Inv |
| invoiced | Invd |
| item tracking | IT |
| journal | Jnl |
| language | Lang |
| ledger | Ledg |
| level | Lvl |
| line | Ln |
| list | Lt |
| local currency | LCY |
| location | Loc |
| mailing | Mail |
| maintenance | Maint |
| management | Mgt |
| manual | Man |
| manufacturing | Mfg |
| manufacturer | Mfr |
| material | Mat |
| marketing | Mktg |
| maximum | Max |
| measure | Meas |
| message | Msg |
| minimum | Min |
| miscellaneous | Misc |
| modify | Mod |
| month | Mth |
| negative | Neg |
| non-inventoriable | NonInvtbl |
| notification | Notif |
| number | No |
| numbers | Nos |
| object | Obj |
| operating | Oper |
| opportunity | Opp |
| order | Ord |
| orders | Ords |
| original | Orig |
| organization | Org |
| outbound | Outbnd |
| Outgoing | Outg |
| output | Out |
| outstanding | Outstd |
| overhead | Ovhd |
| payment | Pmt |
| percent | Pct |
| personnel | Persnl |
| physical | Phys |
| picture | Pic |
| planning | Plng |
| posted | Pstd |
| posting | Post |
| positive | Pos |
| precision | Prec |
| prepayment | Prepmt |
| product | Prod |
| production | Prod |
| production order | ProdOrd |
| project | Proj |
| property | Prop |
| prospect | Prspct |
| purchase | Purch |
| purchases | Purch |
| purchaser | Purchr |
| purchase order | PurchOrd |
| quality | Qlty |
| quantity | Qty |
| questionnaire | Questn |
| quote | Qte |
| radio frequency | RF |
| range | Rng |
| receipt | Rcpt |
| received | Rcd |
| record | Rec |
| records | Recs |
| reconcile | Recncl |
| reconciliation | Recon |
| recurring | Recur |
| reference | Ref |
| register | Reg |
| registration | Regn |
| registered | Regd |
| relation | Rel |
| relations | Rels |
| relationship | Rlshp |
| release | Rlse |
| released | Rlsd |
| remaining | Rem |
| reminder | Rmdr |
| replacement | Repl |
| replenish | Rplnsh |
| replenishment | Rplnsht |
| report | Rpt |
| represent | Rep |
| represented | Repd |
| request | Rqst |
| required | Reqd |
| requirement | Reqt |
| requirements | Reqts |
| requisition | Req |
| reserve | Rsv |
| reserved | Rsvd |
| reservation | Reserv |
| resolution | Resol |
| resource | Res |
| response | Rsp |
| responsibility | Resp |
| retain | Rtn |
| retained | Rtnd |
| return | Ret |
| returns | Rets |
| revaluation | Revaln |
| reverse | Rev |
| review | Rvw |
| round | Rnd |
| rounded | Rndd |
| rounding | Rndg |
| route | Rte |
| routing | Rtng |
| routine | Rout |
| sales & receivables | Sales |
| safety | Saf |
| schedule | Sched |
| second | Sec |
| segment | Seg |
| select | Sel |
| selection | Selctn |
| sequence | Seq |
| serial | Ser |
| serial number | SN |
| service | Serv |
| sheet | Sh |
| shipment | Shpt |
| source | Src |
| special | Spcl |
| specification | Spec |
| specifications | Specs |
| standard | Std |
| frequency | SF |
| statement | Stmt |
| statistical | Stat |
| statistics | Stats |
| stock | Stk |
| stockkeeping unit | SKU |
| stream | Stm |
| structured query language | SQL |
| subcontract | Subcontr |
| subcontracted | Subcontrd |
| subcontracting | Subcontrg |
| substitute | Sub |
| substitution | Subst |
| suggest | Sug |
| suggested | Sugd |
| suggestion | Sugn |
| summary | Sum |
| suspended | Suspd |
| symptom | Sympt |
| synchronize | Synch |
| temporary | Temp |
| total | Tot |
| transaction | Transac |
| transfer | Trans |
| translation | Transln |
| tracking | Trkg |
| troubleshoot | Tblsht |
| troubleshooting | Tblshtg |
| unit of measure | UOM |
| unit test | UT |
| unrealized | Unreal |
| unreserved | Unrsvd |
| update | Upd |
| valuation | Valn |
| value | Val |
| value added tax | VAT |
| variance | Var |
| vendor | Vend |
| warehouse | Whse |
| web shop | WS |
| worksheet | Wksh |
| g/l | GL |
| % | Pct |
| 3-tier | Three-Tier |
| Outlook Synch | Osynch |

View file

@ -0,0 +1,34 @@
---
title: "Unnecessary else"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
`else` should not be used when the last action in the `then` part is an `exit`, `break`, `skip`, `quit`, `error`.
## Bad code
```al
procedure SomeProcedure()
begin
if IsAdjmtBinCodeChanged() then
Error(AdjmtBinCodeChangeNotAllowedErr, ...)
else
Error(BinCodeChangeNotAllowedErr, ...);
end;
```
## Good code
```al
procedure SomeProcedure()
begin
if IsAdjmtBinCodeChanged() then
Error(AdjmtBinCodeChangeNotAllowedErr, ...)
Error(BinCodeChangeNotAllowedErr, ...);
end;
```

View file

@ -0,0 +1,38 @@
---
title: "Unnecessary true/false"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
Do not use `true` or `false` keywords unnecessarily if the expression is already an logical expression.
## Example 1
### Bad code
```al
if IsPositive() = true then
```
### Good code
```al
if IsPositive() then
```
## Example 2
### Bad code
```al
if Complete <> true then
```
### Good code
```al
if not Complete then
```

View file

@ -0,0 +1,63 @@
---
title: "Variable Naming"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
Variables that refer to a AL object must contain the objects name, abbreviated where necessary.
A variable must begin with a capital letter.
Blanks, periods, and other characters (such as parentheses) that would make quotation marks around a variable necessary must be omitted.
If a variable is a compound of two or more words or abbreviations, each word or abbreviation should begin with a capital letter.
## Example 1
### Bad code
```al
WIPBuffer: Record "Job WIP Buffer"
```
### Good code
```al
JobWIPBuffer: Record "Job WIP Buffer"
```
## Example 2
### Bad code
```al
Postline: Codeunit "Gen. Jnl.-Post Line";
```
### Good code
```al
GenJnlPostLine: Codeunit "Gen. Jnl.-Post Line";
```
## Example 3
### Bad code
```al
"Amount (LCY)": Decimal;
```
### Good code
```al
AmountLCY: Decimal;
```
## Tips
The [AL Variable Helper](https://marketplace.visualstudio.com/items?itemName=rasmus.al-var-helper) extension provides Intellisense support to assign correct variable names in AL.

View file

@ -0,0 +1,48 @@
---
title: "Variables Declarations Order"
tags: ["AL","Readability"]
categories: ["Best Practice"]
---
_Created by Microsoft, Described by waldo_
## Description
Variables declarations should be ordered by type. In general, object and complex variable types are listed first followed by simple variables. The order should be:
- Record
- Report
- Codeunit
- XmlPort
- Page
- Query
- Notification
- BigText
- DateFormula
- RecordId
- RecordRef
- FieldRef
- FilterPageBuilder
(Ref: [Microsoft Docs](https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/analyzers/codecop-aa0021))
## Bad code
```al
StartingDateFilter: Text;
Vendor: Record Vendor;
```
## Good code
```al
Vendor: Record Vendor;
StartingDateFilter: Text;
```
## Tips
The [AZ AL Dev Tools/AL Code Outline](https://marketplace.visualstudio.com/items?itemName=andrzejzwierzchowski.al-code-outline) extension adds two new commands to Visual Studio Code to sorts variables.
- `Sort Variables in the Active Editor` : sorts variables in the current editor
- `Sort Variables in the Active Project` : sorts variables in the current project

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -0,0 +1,63 @@
+++
chapter = true
pre = "<b><i class='fas fa-clone'></i> </b>"
title = "Guide to Fork & PR"
weight = 100
+++
## Abstract
AL Guidelines is a community project, and as such YOU are encouraged to submit corrections and new ideas. In order to get your content included, you must submit a pull request to the GitHub Repository (Located here: https://github.com/microsoft/alguidelines\). All Pull Requests are subject to approval by a minimum of three admins.
If You are toying with an idea, but You aren't ready to create a document just yet, you are encouraged to create a project discussion thread here: https://github.com/microsoft/alguidelines/discussions
{{% alert title="Warning" color="warning" %}}
This is a warning.
If You haven't worked in collaboration with "external" GitHub repositories before, please familiarize yourself with that process by visiting:
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests
{{% /alert %}}
## Steps
Now that You have decided that You are ready to contribute, these are the steps to take.
{{% alert title="Note" color="info" %}}
You can read more about this process here:
https://docs.github.com/en/get-started/quickstart/contributing-to-projects
{{% /alert %}}
### Step 1: Fork
In order to work on the repository, You must [Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) the repository.
By forking the repository, You essentially create a copy into Your own account.
Start by going to the GitHub Repository (https://github.com/microsoft/alguidelines\), and press the Fork ![Fork Button](./fork_button.jpg "Fork")
Once You have successfully forked the repository, go to your own GitHub repository : ![Forked Repository Representation](./ForkedRepro.png "Forked repository")
You are now able to clone your own repository to your local pc and start editing using your favorite editor. [Visual Studio Code](https://code.visualstudio.com/) is perfectly fine for this task.
{{% alert title="Note" color="info" %}}
You can read more about forking here:
https://docs.github.com/en/get-started/quickstart/fork-a-repo
{{% /alert %}}
### Step 2: Branch
While not necessarily a must, it is always good practice to create a branch off of your forked repository. That will allow you to work on multiple contributions at the same time and won't have to wait for pull requests to be approved before you can continue on your next contribution.
{{% alert title="Note" color="info" %}}
You can read more about Branches here:
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches
{{% /alert %}}
### Step 3: Pull Request
Once you are happy with your contribution, it's time to create a pull request to propose changes into the main project! This is the final step in producing a fork of someone else's project, and arguably the most important. If you've made a change that you feel would benefit the community as a whole, you should definitely consider contributing back.
To do so, head on over to the repository on GitHub where your project lives. For this example, it would be at `https://www.github.com/<your_username>/alguidelines`. You'll see a banner indicating that your branch is one commit ahead of microsoft:main. Click **Contribute** and then **Open a pull request.**
GitHub will bring you to a page that shows the differences between your fork and the microsoft/alguidelines repository. Click **Create pull request.**
GitHub will bring you to a page where you can enter a title and a description of your changes. _It's important to provide as much useful information and a rationale for why you're making this pull request in the first place._ The project owners needs to be able to determine whether your change is as useful to everyone as you think it is. Finally, click **Create pull request.**

View file

@ -0,0 +1,126 @@
+++
chapter = true
pre = "<b><i class='fas fa-clone'></i> </b>"
title = "Formatting tips"
weight = 100
+++
# Tips and tricks in terms of working with MarkDown and Hugo
## Markdown Cheat Sheet
Here you can find a rather interesting Cheat Sheet regarding markdown: [https://www.markdownguide.org/cheat-sheet](https://www.markdownguide.org/cheat-sheet)
## Code Fences / Syntax highlighting
The syntax to use codefences is with backticks. If you provide the language after the first block of backticks, github will automatically put that in decent syntax highlighting. So, A simple code fence with AL code, can simply be done by:
````
```AL
procedure ALGuidelinesRock()
var
Customer: Record Customer;
begin
Customer.Get('10000');
Customer.Name := 'waldo';
Customer.Modify(true);
end;
```
````
Results in:
```AL
procedure ALGuidelinesRock()
var
Customer: Record Customer;
begin
Customer.Get('10000');
Customer.Name := 'waldo';
Customer.Modify(true);
end;
```
## Diagrams with Mermaid
When providing a documentation, diagrams come in handy. [Mermaid](https://mermaid-js.github.io/mermaid/#/) lets you create diagrams and visualizations using text and code.
For example the following markdown section:
````
```mermaid
classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
```
````
Results in:
```mermaid
classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
```
Can't wait to get started? Use the Mermaid [Live Editor](https://mermaid.live/edit).
## Hugo Shortcodes
Since we're using "Hugo", we can use it's shortcode. Here is a reference: [https://gohugo.io/content-management/shortcodes/](https://gohugo.io/content-management/shortcodes/)
It basically means we are able to use easy notations to do cool things. Let's point out some useful shortcodes:
### Twitter
```
{{</* tweet user="waldo1001" id="1458787011024805892" */>}}
```
makes:
{{< tweet user="waldo1001" id="1458787011024805892" >}}
### YouTube
```
{{</* youtube QVOMCYitLEc */>}}
```
makes:
{{< youtube QVOMCYitLEc >}}
### Figure
```
{{</* figure src="http://www.waldo.be/wp-content/uploads/2021/11/business-central-logo.png" title="Business Central" */>}}
```
makes:
{{< figure src="http://www.waldo.be/wp-content/uploads/2021/11/business-central-logo.png" title="Business Central" >}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,57 @@
---
title: "Manually on Windows 11"
---
This guide will walk You thrugh installing Hugo on a Windows 11 PC. For the official install guide, You can wisit <https://gohugo.io/gettingstarted/installing/>.
## Download Binaries
The path of least resistance is to just download the .zip file from the official Hugo GitHub Repository [here](https://github.com/gohugoio/hugo/releases).
The theme that are used, needs the extended version of Hugo, so make sure to download the **extended** version by ensuring the file name starts with `hugo_extended...`
{{% alert title="info" color="info" %}}
For the purpose of this install guide, we are assuming You will want to follow the "standard" used by Hugo for installing. We will be creating a `Hugo` folder in the root of `C:\`. That folder will have a `Bin` folder for the binaries, and a `Sites` folder for each website You are building.
Once You are done, You should have a folder structure that looks like this:
```text
C:\Hugo
├── Bin # Binaries
└┬─ Sites # Hugo Site Repositories
└── alguidelines # Hugo Source for alguidelines.dev
```
{{% /alert %}}
![image](SelectExtended.png)
After downloading the .zip file, extract the zip-file to `c:\Hugo\Bin`
![image](Extract.png)
![image](ExtractToBin.png)
## Add Hugo to Path
After copying the binaries to Your PC, You will need to add Hugo binaries to the `%PATH%` system environment variables.
To do that, search for `environment`
![image](SearchForEnv.png)
once you see the `Edit the system environment variables`, open it and select `Environment Variables`
![image](SystemProperties.png)
Once the Environment Variables screen is open, highlight the `Path` lines and press the `Edit...` button
![image](EnvironmentVariables.png)
Now press `New` and add the `C:\Hugo\Bin` to the path. Press `OK` and `OK` to save the new `Path`
![image](EnvironmentVariablesPath.png)
Once complete. You should now be able to preview the Hugo site on <http://localhost:1313> by opening a command promt, and open the `C:\Hugo\Sites\alguidelines` folder and execute `Hugo Serve`
![image](HugoServe.png)

View file

@ -0,0 +1,35 @@
---
Title: Devcontainer with VS Code
---
## Use a local devcontainer
If you don't want any local setup (apart from Docker Desktop), but still run your own Hugo instance, you can make use of the preconfigured devcontainer. If you want to learn more about the concept, visit [https://code.visualstudio.com/docs/remote/containers](https://code.visualstudio.com/docs/remote/containers). To use it, you need to take the following steps:
1. Start [Docker Desktop](https://www.docker.com/products/docker-desktop) and [switch to Linux containers](https://docs.docker.com/desktop/windows/#switch-between-windows-and-linux-containers) by right-clicking on the Docker logo in the system tray and selecting "Switch to Linux containers...". If you only see "Switch to Windows containers...", then you are already switched to Linux containers. If anything goes wrong, check if you are on the latest version of Docker Desktop and have [the WSL2 integration enabled](https://docs.docker.com/desktop/windows/wsl/#install). If you have all that in place and it still doesn't work, check the extended installation documentation [here](https://code.visualstudio.com/docs/remote/containers#_installation)
{{% alert title="Consequences of switching" color="info" %}}
When switching to Linux, you will probably see a warning that tells you that you "will not be able to manage the Windows containers until you switch back to Windows containers". That means that the Docker Desktop management GUI can only show either the Windows containers or the Linux containers and if you switch to Linux, you consequently won't see the Windows containers until you switch back. But the Windows containers will continue to run, you won't loose data and you can keep using them e.g. for Business Central development, you just can't manage them through the Docker Desktop GUI
{{% /alert %}}
2. Install the [Remote development extension pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) in Visual Studio Code
3. Run the action "Remote containers: Clone Repository in Container Volume" and select the fork you created. If you haven't done that before, go through the [docs](https://alguidelines.dev/docs/contributing/forkandpr/#step-1-fork).
4. Wait for a bit. When you do this for the first time, it can take a couple of minutes. Next time it will be faster...
5. After a while, you will have VS Code with the cloned repository and the terminal should show something like "Done. Press any key to close the terminal."
6. Run the action "Tasks: Run task" and select "Start local Hugo Server" from the list. If you don't see that entry, you might have to reload your VS Code window and try again
7. After Hugo has generated the site, you will get a notification that offers you to "Open a browser". Click on that and you will see your local instance of the AL guidelines! Again, on the first try it will be a bit slow and sluggish, but the second one should be fast.
8. Now you can make changes and just save them. If you open the terminal, you will see a message that tells you that a change was detected and the site was rebuilt. After that, the change should automatically appear in your browser
Here is a walkthrough of the full process:
<video width=100% controls>
<source src="alguidelines walkthrough.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
## Use GitHub Codespaces
What is also great about this, is that you can also use [GitHub Codespaces](https://github.com/features/codespaces) with that setup. In that case, steps 1-5 become two clicks... Here is another full walkthrough:
<video width=100% controls>
<source src="alguidelines codespace.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>

View file

@ -0,0 +1,22 @@
---
Title: Powershell on Windows 11
description: >
Install Hugo with a simple Powershell Script and chocolatey
---
It is possible to use a powershell script and Chocolatey to install and other dependencies. Execute the following script:
```powershell
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
choco install -y nodejs
choco install -y hugo-extended
```
Once complete, in root of of the repository execute the following commands
```powershell
git submodule update --init --recursive --depth 1
npm install
```

View file

@ -0,0 +1,9 @@
---
title: Install Hugo
---
There are multiple ways to install Hugo for you to properly preview your contributions. Please select the scenario that matches your setup.
For the official install guide, you can visit <https://gohugo.io/gettingstarted/installing/>
{{< youtube G7umPCU-8xc >}}

View file

@ -0,0 +1,31 @@
---
title: "Title Here"
tags: ["AL"]
categories: ["Best Practice"]
---
<!-- This is a guideline, some parts are optional (if there's no content, remove the whole paragraph). -->
<!-- The "Readability" and "Performance" tags are often used. You can, however, add multiple tags, but please do not change the Category -->
_Created by <!-- John Smith --><!--, Cronus International.--> Described by <!-- Jane Doe--><!--, Contoso, LLC-->_
## Description
In depth description on what this Pattern is all about
- basic components
- how the interact
- steps to implement
- considerations to take
## Bad code
```al
PutCodeblocksHere()
```
## Good code
```al
PutCodeblocksHere()
```

View file

@ -0,0 +1,46 @@
---
title: "Title Here"
tags: ["AL"]
categories: ["Pattern"]
---
<!-- This is a guideline, some parts are optional (if there's no content, remove the whole paragraph). -->
_Created by <!-- John Smith --><!--, Cronus International.--> Described by <!-- Jane Doe--><!--, Contoso, LLC-->_
## Abstract
Short, descriptive and easy to remember description of this pattern.
## Context
Sets the stage where the pattern takes place. 1-2 sentences.
## Problem
What happens before this pattern is used? How can it go wrong? 1-5 lines.
## Description
In depth description on what this Pattern is all about
- basic components
- how the interact
- steps to implement
- considerations to take
## Usage
If applicable: where is it used in an app. You can refer to any app, BaseApp, or a (public) ISV app.
## Benefits
1-2 sentences: what did you just solve
## When not to use
Usually, there are occasions where NOT to implement the pattern. List the disadvantages of this pattern here.
## List of references
Youtube-link? BaseApp? Tweet? ...

View file

@ -0,0 +1,12 @@
---
title: "Templates"
---
We have created some template-files that you can simply copy and use. Look at them as "Patterns for describing patterns"
We currently offer the following templates:
- for [Patterns](/contributing/templates/patterns/) ([raw](https://raw.githubusercontent.com/microsoft/alguidelines/main/content/docs/Contributing/Templates/Patterns/index.md))
- for [Best Practice](/contributing/templates/bestpractice/) ([raw](https://raw.githubusercontent.com/microsoft/alguidelines/main/content/docs/Contributing/Templates/BestPractice/index.md))
opening the "raw" link, will allow for the best copy/paste result.

View file

@ -0,0 +1,9 @@
+++
chapter = true
pre = "<b><i class='fas fa-clone'></i> </b>"
title = "Understanding the Approval Process"
weight = 100
+++
(coming soon)

View file

@ -0,0 +1,27 @@
+++
chapter = true
pre = "<b><i class='fas fa-clone'></i> </b>"
title = "Contributing"
weight = 100
+++
First off, we're glad you want to help! The project team is kind and helpful, so if you're not sure if you have a good first contribution, make a [Discussion](https://github.com/microsoft/alguidelines/discussions/) about it or even just create your first try. You'll get feedback and we will be happy to help refine it, if it even needs it.
## Code of Conduct
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
## Steps to Contribute
* [Guide to Fork & PR](/docs/contributing/forkandpr/)
* Templates:
- For [patterns](/docs/contributing/templates/patterns/)
- For [guidelines](/docs/contributing/templates/guidelines/)
* [Understanding the Approval Process](/docs/contributing/theapprovalprocess/)
Here are some [tips and tricks in terms of working with Markdown and Hugo](/docs/contributing/formattingtips/).

View file

@ -0,0 +1,19 @@
+++
chapter = true
title = "2. Anti-Patterns"
weight = 130
tags = ["C/AL"]
+++
Some of the software development practices, had **not** stood the test of time. Despite that, some are still being used today by developers everywhere.
"An **anti-pattern** (or **antipattern**) is a common response to a recurring problem that is usually ineffective and risks being highly counterproductive" (from [Wikipedia][anchor0])
Since almost the beginning of the NAV Design Patterns project, we talked about documenting the anti-patterns - but never found the time. Until, spontaneously, the April 1st 2015 article had practically wrote itself in a couple of hours, with priceless contributions coming from Andreas, Elly, Nikola - and last but not least, waldo.
Best regards,
Bogdana Botez
[anchor0]: http://en.wikipedia.org/wiki/Anti-pattern

View file

@ -0,0 +1,75 @@
+++
title = "Nav Upgrade"
weight = 840
tags = ["C/AL"]
+++
## Anti-Patterns in NAV Upgrade
_By Carlos Raul Garcia and Bogdana Botez at Microsoft Development Center Copenhagen_
[![ ][image0]][anchor0]
**Context**: when NAV is upgraded, whether on-premises or in the cloud, developers have the chance to write upgrade code to move data across changing data structures. Writing good quality code will help successful upgrades.
### General on upgrade
**Problem:** assuming that the upgrade table contains data.
If the table is empty, it means that either the upgrade has run, or there was no data in the original tenant; in both cases, the upgrade code should exit immediately.
**Solution:** if using an upgrade table, always validate that the table contains data before doing anything.
### Upgrade code, can it be rerun safely?
**Problem**: if the upgrade code is not written in a way that makes it runnable twice ([idempotent][anchor1]), then several failures can happen, including something as critical as data corruption.
In on premise NAV installations, if something fails at upgrade, there is no way to run only the "remaining" tasks. You will need to run the whole upgrade again, and might end-up with data that you cannot trust.
What about the cloud? In Platform As A Service (PaaS), in some situations, the upgrade code needs to be run twice (for example, when moving tenants from a broken/frozen VM to a healthy one).
**Solution:** Make sure each of your upgrade procedures only kicks in if it didn't run before.
**Examples**
The examples below have happened in real live NAV PaaS upgrade:
**Table data overwrite**
* **Problem**: at upgrade, a new column has bee­n added to a table and initialized with default values. In the meanwhile, during production, some of the default values are changed to production real life values. The second time the upgrade runs, those values will be overwritten with defaults, any personalization lost.
* **Solution:** before initializing with default values, check if non-default values exist.
**Crash on math operations**
* **Problem:** one tenant upgrade managed to divide by zero, by assuming a non-zero value.
* **Solution:** don't assume values can never be zero, always check before using them in divisions.
**Use of external components**
* **Problem:** a one-time registration through web services to an external service failed when attempting to register a second time.
* **Solution:** check if already registered, before attempting again.
### Parallelism
**Problem**: Upgrade procedures can be run in parallel, causing issues when different procedures attempt to modify the same table at the same time.
When modifications to the same table are being made from two or more different procedures, there is no guarantee on sequential run, or on a certain order they will be run in.
**Solution**: if sequential or ordered execution is needed, make the affected upgrade procedures local and call them all, in the desired sequence, from a public upgrade procedure.
### Access to cloud machines
**Problem:** dependencies on manual installation steps do not fit in the cloud.
If Dynamics NAV is installed on-premises, then any additional setup (like dependencies of external dlls, manual configuration steps etc.) can be done manually or semi-manually by the IT admin, at first setup and upgrade.
In the cloud, NAV partners don't have access to the machines -- hence they cannot deploy and configure those external dependencies as they did in the old on-premises installations.
**Solution:** Don't assume you will have access to PaaS or SaaS machines. Build your solution in such a way that it doesn't depend on executing manual configurations on the host machine.
[anchor0]: upgrade.png
[anchor1]: http://stackoverflow.com/questions/1077412/what-is-an-idempotent-operation#1077421
[image0]: upgrade.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,95 @@
+++
title = "Reusable Bugs"
weight = 1020
tags = ["C/AL"]
+++
_By Bogdana Botez, Andreas Moth, Eric Wauters (waldo), Elly Nkya, Nikola Kukrika_
_April 1st, 2015_
## Abstract
It is difficult to come up with new and different bugs in each release, and it is a waste of resources to not use the ones which already had proven successful in the past. To avoid reinventing the wheel, we propose to come up with new innovative ways to create bugs that are reusable and generic enough to be used in various places of the application.
## Examples
**Option Strings**
One example of a reusable bug is to find a heavily used table, like table 36 Sales Header, and observe one of the more important fields of type Option, for example Document Type. The OptionString property has the following value: Quote,Order,Invoice,Credit Memo,Blanket Order,Return Order, which you should update to add one option, for example Transport Order in the beginning.
The main benefit of this reusable bug is that code changed in one place, has impact in multiple sides on the application: document creation and handling, posting etc.
**Application Management**
Codeunit 1, ApplicationManagement is a good place for creating reusable bugs. A simple INSERT on the RecRef on the first line of OnDatabaseInsert will create a sure and versatile bug that is reusable all over the application. Redundancy on database insertion ensures that data is surely conveyed to the data storage layer, twice.
**God objects**
We are considering to no longer make localization builds for countries. It consumes lab resources to keep running multiple country builds. Instead, we will merge everything into one single build. This is a bigger scale implementation of the ["God object"][anchor0]. Inside this unique build, we will use IF statements and sporadically CASE statements to select each country's behavior. For more help on how to use IFs, see also the IF .. THEN|ELSE C/AL Coding Guideline.
**Field length economy**
When you post a document, make sure to transfer data to a field that is smaller than the field you are assigning from. This will not immediately be caught and will only hurt a subset of the customers who uses Microsoft Dynamics NAV to its fullest.
## Guidelines
When bug addition is not entirely obvious, there is a second way to approach the problem. By following some general coding best practices like the ones described below, reliable bug innovation is facilitated and can come naturally as a collateral effect.
**Code structure**
Put everything in one function and only use comments to explain the structure of your code. And don't use functions - because this only complicates things... having to navigate from function to function, and completely lose track of where you are in the business logic.
On top of that .. put everything in one codeunit. Because also that will simplify and make your structure more readable.
Use Hungarian Notation on your variables, because at any time, you need to know what type, and what context your variable is on.
Declare all your functions and variables global, so they are available at any time.
**Don't do Unit Testing**
Unit testing adds complexity and extra time to the stuff you're doing. Also, it eats up extra codeunits which means: it costs money. You will never be able to foresee all scenarios possible, so you're destined to forget and not test everything. So you will save time in not doing unit testing.
**Never add images to actions**
Because there is an image by default. When you don't provide an image on an action on a page, the application will foresee a ball... and when you never do it, your application will have a very consistent way of showing your actions, by providing that picture of that ball. On top of that, you'll save time.
**Do not care about ControlIDs**
When you're doing development of your product, do not care about ControlIDs, and just leave the Offset ID to the default value of 0\. This way, when merging, you will receive nice notifications, saying both you and Microsoft have added functions in that objects. You can use this feature to document all these places.
**Hooks**
Never apply the hook pattern. Hooks will only reduce upgrade time. This means, you will only shortly enjoy using the AMU (Application Merge Utilities). The more you change in default application, the longer it takes to upgrade, the longer you will enjoy the toolkit
This can be taken one level higher. Simply you are not hardcore if you do not use notepad to resolve all of the merge issues.
**How to use RecRef**
Why fuss around declaring specific table variables, just generalize, all you need is one, two, or perhaps three RecRef variables, with a few IFs and CASEs here and there for reflection, to carry you all the way.
**Arguments**
Using only a few arguments on the functions is a sign of a weak developer. Stick in as many arguments as possible on the function, even if you are not using them, they could be useful in the future.
**Just another field / action**
Thinking of the design is overrated, each problem can be solved by adding an additional field or the table/page or with adding another action. We all know this has worked well in the past.
**Reusability**
We have decided that each time we fix a bug, we now also explain how it can be applied as a pattern. We then use anti-virus software to search for these patterns, to make sure we do not re-introduce these bugs anywhere else in NAV.
**Business logic placement**
As a best practice, we have also decided to move code into pages. Business logic should no longer be in tables and codeunits, but instead pages should know and be aware of the context and update it accordingly. As opposite to tables and codeunits, pages are aware of the context.
## Conclusion
Happy April Fools' Day.
Disclaimer: this is inspired from IETF documentation published on April 1st, like for example the revolutionizing [IP over Avian Carriers][anchor1] standard.
[anchor0]: http://en.wikipedia.org/wiki/God_object
[anchor1]: http://en.wikipedia.org/wiki/IP_over_Avian_Carriers

View file

@ -0,0 +1,28 @@
+++
chapter = true
title = "3. CAL Coding Guidelines"
weight = 150
tags = ["C/AL"]
categories = ["Best Practice"]
+++
We've decided to publish our current C/AL coding guidelines. They are actual, as per January 2015 when this is published (but might fall out of sync as time goes by).
You can also [download the C/AL coding guidelines as pdf,][anchor0] all in one document. In contrast, on this wiki, the coding guidelines are published individually. The reason is: give you the chance to comment and share your oppinion on each one. Thanks to [waldo][anchor1] for this idea and for helping out.
The guidelines are debatable - and it is good when they are generating debate. There is variation of opinion on the rules at Microsoft too. The plan is to simply expose what we use now. And more important, to say that guidelines could be used. Debate on individual guidelines can become heated for any programming language, but the benefit of using some guidelines stays.
For us, those guidelines are enforced at check-in time - we are using a tool which verifies and only allows compliant check-ins. While this tool is internal and not ready to publish, we had anyways decided to open up and present the rules we use to the community, as inspiration.
Question: Since we're having the guidelines, how come there is still C/AL code in NAV which doesn't respect them?
Answer: all new C/AL code is bound to follow the guidelines (else it cannot be checked-in). However, the code that existed before the rules - it does not. We had done cleanup in a certain degree. Now we're gradually improving the old code base as we visit various objects in order to add new functionality, however chances are that code we didn't touch in a long time had remained in its old form.
We're looking forward to your comments. Where you can, do provide concrete examples of the alternatives, Good and Bad.
{{< youtube z6skKy0pkmU >}}
[anchor0]: /files/CAL-Coding-Guidelines-at-Microsoft-Development-Center-Copenhagen.pdf "download the C/AL coding guidelines as pdf"
[anchor1]: /members/waldo/default.aspx "waldo"
[anchor2]: https://www.youtube.com/watch?v=z6skKy0pkmU&list=PLhZ3P-LY7CqmVszuvtJLujFyHpsVN0U_w&index=26

View file

@ -0,0 +1,11 @@
+++
title = "Design"
weight = 490
tags = ["C/AL"]
categories = ["Best Practice"]
+++
## C/AL Coding Guidelines
## **Design**
Find the C/AL guidelines by expanding the menu in the left.

View file

@ -0,0 +1,27 @@
+++
title = "By Reference Parameters"
weight = 280
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not declare parameters by reference if their values are not intended to be changed.
Unintentional value changes might propagate. Also, it might lead people to believe that value changes are intended.
Bad code
LOCAL PROCEDURE ShowMessage@15(VAR Text@1000 : Text[250]);
BEGIN
Text := GetMessageText;
IF (Text <> '') AND GenJnlLineInserted THEN
MESSAGE(Text);
END;
Good code
LOCAL PROCEDURE ShowMessage@15(Text@1000 : Text[250]);
BEGIN
Text := GetMessageText;
IF (Text <> '') AND GenJnlLineInserted THEN
MESSAGE(Text);
END;

View file

@ -0,0 +1,20 @@
+++
title = "Class Coupling"
weight = 320
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not write functions that have high class coupling. This makes the code hard to maintain.
Bad code
Any procedure / trigger that has class coupling of > 30
Good code
Any procedure / trigger that has class coupling of <= 30\.
Class coupling is computed by summing the unique instances of the following in a code block:
- every unique usage of a complex C/AL data type (table, codeunit, etc) as 1\.
- every unique usage of a DotNet type as 1\.

View file

@ -0,0 +1,24 @@
+++
title = "Cyclomatic Complexity"
weight = 460
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not write functions that have high cyclomatic complexity. This makes the code hard to maintain.
Bad code
Any procedure / trigger that has a cyclomatic complexity > 25, using the CC3 version mentioned in [this article][anchor0].
Good code
Any procedure / trigger that has a cyclomatic complexity <= 25, using the CC3 version.
The CC3 version is computed by summing the following in a code block:
- each IF statement as 1\.
- each entire CASE as 1\.
[anchor0]: http://www.aivosto.com/project/help/pm-complexity.html

View file

@ -0,0 +1,7 @@
+++
title = "Encapsulate Local Functionality"
weight = 530
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Any function used local must be defined as local.

View file

@ -0,0 +1,31 @@
+++
title = "FINDSET FINDFIRST FINDLAST"
weight = 600
tags = ["C/AL"]
categories = ["Best Practice"]
+++
FINDSET, FIND('+') or FIND('-') should only be used when NEXT is used and vice versa.
Bad code
IF Cust.FIND('-') THEN
ERROR(CustIsBlockErr)
Good code
IF Cust.FINDFIRST THEN
ERROR(CustIsBlockErr)
Bad code
IF Cust.FINDFIRST THEN
REPEAT
...
UNTIL Cust.NEXT = 0;
Good code
IF Cust.FINDSET THEN
REPEAT
...
UNTIL Cust.NEXT = 0;

View file

@ -0,0 +1,51 @@
+++
title = "Initialized Variables"
weight = 660
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Variables should always be set to a specific value, before they are used.
Bad code
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
VAR
Pegging@1001 : Boolean;
BEGIN
IF Pegging THEN
CurrQuantity := CurrentPurchLine."Quantity (Base)"
ELSE
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
END;
Good code
PROCEDURE SetPurchLine@22(VAR CurrentPurchLine@1000 : Record 39);
VAR
Pegging@1001 : Boolean;
BEGIN
Pegging := IsPegging(CurrentPurchLine);
IF Pegging THEN
CurrQuantity := CurrentPurchLine."Quantity (Base)"
ELSE
CurrQuantity := CurrentPurchLine."Outstanding Qty. (Base)";
END;
Bad code
// In the example below, the function will always return FALSE.
PROCEDURE GetItemsToPlan@22() : Boolean;
BEGIN
SETRANGE("Document Type","Document Type"::Order);
...
FINDSET
END;
Good code
PROCEDURE GetItemsToPlan@22() : Boolean;
BEGIN
SETRANGE("Document Type","Document Type"::Order);
...
EXIT(FINDSET)
END;

View file

@ -0,0 +1,43 @@
+++
title = "Maintainability Index"
weight = 770
tags = ["C/AL"]
categories = ["Best Practice"]
+++
[Maintainability Index][anchor0]: Do not write functions that have a very low maintainability index. This makes the code hard to maintain.
Bad code
Any procedure / trigger that has a maintainability index < 20
Good code
Any procedure / trigger that has a maintainability index >= 20\.
The Maintainability Index is computed as a function:
- Lines Of Code (inverse proportional)
- the Halstead Volume
- Cyclomatic Complexity (inverse proportional).
More info
* [Halstead Volume][anchor1]
* [Cyclomatic Complexity][anchor2]
Bad code
Any procedure / trigger that is > 100 lines of code
Good code
Any procedure / trigger that is <= 100 lines of code.
A full C/AL Statement counts as 1 line of code
[anchor0]: http://blogs.msdn.com/b/codeanalysis/archive/2007/11/20/maintainability-index-range-and-meaning.aspx
[anchor1]: http://en.wikipedia.org/wiki/Halstead_complexity_measures
[anchor2]: http://www.aivosto.com/project/help/pm-complexity.html

View file

@ -0,0 +1,35 @@
+++
title = "Parameter Placeholders"
weight = 920
tags = ["C/AL"]
categories = ["Best Practice"]
+++
The number of parameters passed to a string must match the placeholders.
Bad code
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
...
ERROR(CannotDeleteLineErr,TABLECAPTION);
Good code
CannotDeleteLineErr@1005 : TextConst 'ENU=You cannot delete this line because one or more rating values exists.';
...
ERROR(CannotDeleteLineErr);
Bad code
CannotUseThisFieldErr@1020 : TextConst 'ENU=You cannot use this field for %2 fields.';
...
ERROR(CannotUseThisFieldErr,0,Field.Class);
Good code
CannotUseThisFieldErr@1020 : TextConst 'ENU=You cannot use this field for %1 fields.';
...
ERROR(CannotUseThisFieldErr,Field.Class);
###

View file

@ -0,0 +1,23 @@
+++
title = "Static Object Invocation"
weight = 1160
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Call objects statically whenever possible. It reduces extra noise and removes extra variables. Downside: changing the name of the object which is called statically will need a code update.
Bad code
LOCAL PROCEDURE Code@1();
VAR
CAJnlPostBatch@1001 : Codeunit 1103;
BEGIN
CAJnlPostBatch.Run(CostJnlLine);
END;
Good code
LOCAL PROCEDURE Code@1();
BEGIN
CODEUNIT.RUN(CODEUNIT::"CA Jnl.-Post Batch",CostJnlLine);
END;

View file

@ -0,0 +1,27 @@
+++
title = "Unreachable Code"
weight = 1310
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not write code that will never be hit.
It affects code readability and can lead to wrong assumptions.
Bad code
IF Type <> Type::FIELD THEN BEGIN
...
ERROR(...);
RecRef.CLOSE;
END;
Good code
IF Type <> Type::FIELD THEN BEGIN
...
RecRef.CLOSE;
ERROR(...);
END;

View file

@ -0,0 +1,40 @@
+++
title = "Unused Initialized Variables"
weight = 1320
tags = ["C/AL"]
categories = ["Best Practice"]
+++
The value assigned to a variable must be used. Else the variable is not necessary.
Bad code
PROCEDURE AddEntities@1(FilterStr@1000 : Text[250]);
VAR
Vendor@1001 : Record 23;
Count@1002 : Integer;
BEGIN
Count := 0;
Vendor.SETFILTER("No.",FilterStr);
IF Vendor.FINDSET THEN
REPEAT
"User ID" := USERID;
"Vendor No." := Vendor."No.";
IF INSERT THEN
Count += 1;
UNTIL Vendor.NEXT = 0;
END;
Good code
PROCEDURE AddEntities@1(FilterStr@1000 : Text[250]);
VAR
Vendor@1001 : Record 23;
BEGIN
Vendor.SETFILTER("No.",FilterStr);
IF Vendor.FINDSET THEN
REPEAT
"User ID" := USERID;
"Vendor No." := Vendor."No.";
IF INSERT THEN;
UNTIL Vendor.NEXT = 0;
END;

View file

@ -0,0 +1,46 @@
+++
title = "Unused Variables"
weight = 1330
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not declare variables that are unused.
Unused variables affect readability.
Bad code
PROCEDURE CheckPostingDate@23(CaptionEntryNo@1005 : Text[50]);
BEGIN
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
ERROR(DateNotAllowedErr,Caption,EntryNo)
IF PostingDate > MaxPostingDate THEN
MaxPostingDate := PostingDate;
END
Good code
PROCEDURE CheckPostingDate@23();
BEGIN
IF GenJnlCheckLine.DateNotAllowed(PostingDate) THEN
ERROR(DateNotAllowedErr,Caption,EntryNo);
IF PostingDate > MaxPostingDate THEN
MaxPostingDate := PostingDate;
END;
Bad code
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
VAR
ItemEntry@1000 : Record 32;
Quantity@1003 : Integer;
BEGIN
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
END;
Good code
PROCEDURE IsReturned@14(EntryNo@1002 : Integer) : Decimal;
BEGIN
EXIT(-OutboundApplied(EntryNo,TRUE) - InboundApplied(EntryNo,TRUE));
END;

View file

@ -0,0 +1,61 @@
+++
title = "Variable Capacity Mismatch"
weight = 1410
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not assign a value to a variable whose capacity is smaller.
It will throw an error at runtime.
Bad code
FileName@1010 : Text[250];
...
UploadedFileName@1016 : Text[1024];
...
FileName := UploadedFileName;
Good code
FileName@1010 : Text[1024];
...
UploadedFileName@1016 : Text[1024];
...
FileName := UploadedFileName;
Bad code
FileName@1010 : Text[250];
...
UploadedFileName@1016 : Text[1024];
...
FileName := UploadedFileName;
Good code
FileName@1010 : Text[250];
...
UploadedFileName@1016 : Text[1024];
...
FileName := COPYSTR(UploadedFileName,1,250); // In case only the first 250 chars are needed. Similar for fields
Bad code
VAR
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
Subject@1002 : Text[50];
...
BEGIN
...
Subject := ExceededNumberTxt;
Good code
VAR
ExceededNumberTxt@001 : 'ENU=Warning: Exceeded number of unsent documents/requests'
Subject@1002 : Text[100];
...
BEGIN
...
Subject := ExceededNumberTxt';

View file

@ -0,0 +1,32 @@
+++
title = "WITH Scope Name Collision"
weight = 1450
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Do not use the WITH scope when it has a variable whose name is the same as a local variable. This can lead to wrong code assumptions.
**Given that**
"Contract Type" is a field on table ServiceContractHeader, then in the following example there is a parameter name clash with the field name. Which one will be used?
Bad code
PROCEDURE InsertData@1("Contract Type"@1000 : Option...);
...
BEGIN
...
WITH ServiceContractHeader DO BEGIN
...
DimMgt.InsertServContractDim(...,"Contract Type","Contract No.",0,...);
END;
Good code
PROCEDURE InsertData@1(ContractType@1000 : Option...);
...
BEGIN
...
WITH ServiceContractHeader DO BEGIN
...
DimMgt.InsertServContractDim(...,ContractType,"Contract No.",0,...);
END;

View file

@ -0,0 +1,208 @@
+++
title = "Internally used DotNet Types"
weight = 690
tags = ["C/AL"]
categories = ["Best Practice"]
+++
_(Dynamics NAV 2015)_
**Dot Net Types**
'mscorlib'.System.Convert
'mscorlib'.System.Globalization.CultureInfo
'mscorlib'.System.Globalization.DateTimeStyles
'mscorlib'.System.Globalization.NumberStyles
'mscorlib'.System.Type
'mscorlib'.System.Array
'mscorlib'.System.EventArgs
'mscorlib'.System.Security.Cryptography.SHA512Managed
'mscorlib'.System.Security.Cryptography.HashAlgorithm
'mscorlib'.System.Text.Encoding
'mscorlib'.System.Text.UTF8Encoding
'mscorlib'.System.Environment
'mscorlib'.System.IO.Directory
'mscorlib'.System.IO.Path
'mscorlib'.System.IO.File
'mscorlib'.System.IO.FileAttributes
'mscorlib'.System.Collections.ArrayList
'mscorlib'.System.Collections.IEnumerator
'mscorlib'.System.Collections.Generic.IEnumerator\`1
'mscorlib'.System.TimeSpan
'mscorlib'.System.DateTime
'mscorlib'.System.DateTimeKind
'mscorlib'.System.DateTimeOffset
'mscorlib'.System.Decimal
'mscorlib'.System.String
'System'.System.Diagnostics.Process
'System'.System.Diagnostics.ProcessStartInfo
'System'.System.IO.Compression.CompressionMode
'System'.System.IO.Compression.GZipStream
'System'.System.Uri
'System'.System.UriPartial
'System.Data'.System.Data.DataColumn
'System.Data'.System.Data.DataTable
'System.Data'.System.Data.DataRow
'System.Web'.System.Web.HttpUtility
'System.Windows.Forms'.System.Windows.Forms.DialogResult
'System.Windows.Forms'.System.Windows.Forms.FileDialog
'System.Windows.Forms'.System.Windows.Forms.OpenFileDialog
'System.Windows.Forms'.System.Windows.Forms.SaveFileDialog
'System.Windows.Forms'.System.Windows.Forms.FolderBrowserDialog
'System.Xml'.\*
'DocumentFormat.OpenXml'.\*
'mscorlib'.System.IO.DirectoryInfo
'mscorlib'.System.IO.FileInfo
'Microsoft.Dynamics.Nav.Client.CodeViewerTypes'.Microsoft.Dynamics.Nav.Client.CodeViewerTypes.BreakpointCollection
'Microsoft.Dynamics.Nav.Client.CodeViewerTypes'.Microsoft.Dynamics.Nav.Client.CodeViewerTypes.VariableCollection
'Microsoft.Dynamics.Nav.SMTP'.Microsoft.Dynamics.Nav.SMTP.SmtpMessage
'Microsoft.Dynamics.Nav.Management.DSObjectPickerWrapper'.\*
'Microsoft.Dynamics.Nav.Timer'.\*
'Microsoft.Dynamics.Nav.DO.ClientProxyWrapper'.\*
'Microsoft.Dynamics.Nav.Client.BusinessChart'.\*
'Microsoft.Dynamics.Nav.Client.BusinessChart.Model'.\*
'Microsoft.Dynamics.Nav.Integration.Office'.\*
'Microsoft.Dynamics.Nav.Integration.Office.Mock'.\*
'Microsoft.Dynamics.Nav.EwsWrapper'.\*
'Microsoft.Dynamics.Nav.EwsWrapper.ALTestHelper'.\*
'Microsoft.Dynamics.NAV.OLSync.OLSyncSupplier'.\*
'Microsoft.Dynamics.Nav.OLSync.Common'.\*
'Microsoft.Dynamics.Nav.NavUserAccount'.\*
'Microsoft.Dynamics.Nav.OpenXml'.\*
'Microsoft.Dynamics.Nav.RapidStart'.\*
'Microsoft.Dynamics.Framework.RapidStart.Common'.\*
'Microsoft.Dynamics.Nav.Client.TimelineVisualization'.Microsoft.Dynamics.Nav.Client.TimelineVisualization.
VisualizationScenarios
'Microsoft.Dynamics.Framework.UI.WinForms.DataVisualization.Timeline'.Microsoft.Dynamics.Framework.UI.
WinForms.DataVisualization.TimelineVisualization.DataModel+TransactionChangesRow
'Microsoft.Dynamics.Framework.UI.WinForms.DataVisualization.Timeline'.Microsoft.Dynamics.Framework.UI.
WinForms.DataVisualization.TimelineVisualization.DataModel+TransactionChangesDataTable
'Microsoft.Dynamics.Framework.UI.WinForms.DataVisualization.Timeline'.Microsoft.Dynamics.Framework.UI.
WinForms.DataVisualization.TimelineVisualization.DataModel+TransactionRow
'Microsoft.Dynamics.Framework.UI.WinForms.DataVisualization.Timeline'.Microsoft.Dynamics.Framework.UI.
WinForms.DataVisualization.TimelineVisualization.DataModel+TransactionDataTable
'Microsoft.Office.Interop.Word'.\*
'Microsoft.Office.Interop.Excel'.\*
'Microsoft.Dynamics.BAPIWrapper'.\*
'Microsoft.Dynamics.Nav.Types'.Microsoft.Dynamics.Nav.Types.ConfigSettings
'Microsoft.Dynamics.Nav.DocumentService'.\*
'Microsoft.Dynamics.Nav.DocumentService.Types'.\*
'mscorlib'.System.IO.StreamWriter
'Microsoft.Dynamics.Nav.Client.TimelineVisualization'.Microsoft.Dynamics.Nav.Client.TimelineVisualization.
InteractiveTimelineVisualizationAddIn
'System'.System.ComponentModel.CancelEventArgs
'System'.System.Text.RegularExpressions.Regex
'System'.System.Text.RegularExpressions.RegexOptions
'mscorlib'.System.IO.StreamReader
'System.Windows.Forms'.System.Windows.Forms.Control
'System.Windows.Forms'.System.Windows.Forms.ControlEventArgs
'System.Windows.Forms'.System.Windows.Forms.DragEventArgs
'System.Windows.Forms'.System.Windows.Forms.GiveFeedbackEventArgs
'System.Windows.Forms'.System.Windows.Forms.HelpEventArgs
'System.Windows.Forms'.System.Windows.Forms.InvalidateEventArgs
'System.Windows.Forms'.System.Windows.Forms.KeyEventArgs
'System.Windows.Forms'.System.Windows.Forms.KeyPressEventArgs
'System.Windows.Forms'.System.Windows.Forms.LayoutEventArgs
'System.Windows.Forms'.System.Windows.Forms.MouseEventArgs
'System.Windows.Forms'.System.Windows.Forms.PaintEventArgs
'System.Windows.Forms'.System.Windows.Forms.PreviewKeyDownEventArgs
'System.Windows.Forms'.System.Windows.Forms.QueryAccessibilityHelpEventArgs
'System.Windows.Forms'.System.Windows.Forms.UICuesEventArgs

View file

@ -0,0 +1,12 @@
+++
title = "Internationalization"
weight = 700
tags = ["C/AL"]
categories = ["Best Practice"]
+++
## C/AL Coding Guidelines
## **Internationalization**
Find the C/AL guidelines by expanding the menu in the left.

View file

@ -0,0 +1,19 @@
+++
title = "Using Calcdate"
weight = 1370
tags = ["C/AL"]
categories = ["Best Practice"]
+++
CALCDATE should only be used with DateFormula variables. Alternatively the string should be enclosed using the <> symbols.
Bad code
IF ReservEntry."Expected Receipt Date" >
CALCDATE('-' + FORMAT("Dampener (Time)") + FirstDate)
THEN
Good code
IF ReservEntry."Expected Receipt Date" >
CALCDATE('<-' + FORMAT("Dampener (Time)") + FirstDate + '>')
THEN

View file

@ -0,0 +1,11 @@
+++
title = "Localizability"
weight = 750
tags = ["C/AL"]
categories = ["Best Practice"]
+++
## C/AL Coding Guidelines
## **Localizability**
Find the C/AL guidelines by expanding the menu in the left.

View file

@ -0,0 +1,28 @@
+++
title = "CaptionML on System Pages"
weight = 300
tags = ["C/AL"]
categories = ["Best Practice"]
+++
CaptionML should always be specified on a page field for a system table. By default, system tables do not have captions, so if you need to use them in the UI then captions need to be added.
Bad code
...
{ 2 ;2 ;Field ;
SourceExpr=Name }
...
OBJECT Table 2000000000 User
...
{ 2 ; ;Name ;Text50 }
Good code
...
{ 2 ;2 ;Field ;
CaptionML=ENU=Name;
SourceExpr=Name }
...
OBJECT Table 2000000000 User
...
{ 2 ; ;Name ;Text50 }

View file

@ -0,0 +1,24 @@
+++
title = "FIELDCAPTION and TABLECAPTION"
weight = 580
tags = ["C/AL"]
categories = ["Best Practice"]
+++
For user messages, errors etc., use FIELDCAPTION not FIELDNAME and TABLECAPTION not TABLENAME.
Reason:
1. The correct translation will be automatically used.
2. If the caption/name changes, then there will be a single point of change needed.
Bad code
```al
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDNAME("Location Code"),...)
```
Good code
```al
IF NOT CONFIRM(UpdateLocationQst,TRUE,FIELDCAPTION("Location Code"),...)
```

View file

@ -0,0 +1,26 @@
+++
title = "Global Text Constants"
weight = 610
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Declare Text Constant as global variables.
Bad code
```al
PROCEDURE GetRequirementText@6(...) : Text[50];
VAR
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
BEGIN
```
Good code
```al
VAR
RequirementOptionsTxt@1002 : TextConst 'ENU=Shipment,Receive,Pick,Put-Away';
...
PROCEDURE GetRequirementText@6(...) : Text[50];
BEGIN
```

View file

@ -0,0 +1,47 @@
+++
title = "Use Text Constants"
weight = 1360
tags = ["C/AL"]
categories = ["Best Practice"]
+++
Pass user messages using Text Constants. It makes translation easy.
Bad code
```al
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment "';
...
IF CONFIRM(ImportAttachmentQst + Caption +'?',TRUE) THEN BEGIN
```
Good code
```al
ImportAttachmentQst@1021 : TextConst 'ENU="Import attachment %1?"';
...
IF CONFIRM(STRSUBSTNO(ImportAttachmentQst, Caption),TRUE) THEN BEGIN
```
Bad code
```al
...
IF NOT
CONFIRM(
STRSUBSTNO(
'Difference on Periodic entries: %1 on %2' +
'Do you want to continue?',Balance,Date),
TRUE)
THEN
ERROR('Program terminated by the user');
```
Good code
```al
DiffOnPeriodEntiesQst@100 : TextConst 'ENU="Difference on Periodic entries: %1 on %2\\ Do you want to continue?"';
ProgramTerminatedErr@200 : TextConst 'ENU="Program terminated by the user"';
...
IF NOT CONFIRM(STRSUBSTNO(DiffOnPeriodEntiesQst,Balance,Date),TRUE) THEN
ERROR(ProgramTerminatedErr);
```

View file

@ -0,0 +1,25 @@
+++
title = "Using OptionCaptionML"
weight = 1380
tags = ["C/AL"]
categories = ["Best Practice"]
+++
The OptionCaptionML should be filled in for sourceexpression using option data types.
Bad code
{ 30 ;TextBox ;17850;0 ;150 ;423 ;Name=Selection;
SourceExpr=Selection;
DataSetFieldName=Selection }
...
Selection@1008 : 'Open,Closed,Open and Closed';
...
Good code
{ 30 ;TextBox ;17850;0 ;150 ;423 ;Name=Selection;
OptionCaptionML=ENU=Open,Closed,Open and Closed;
SourceExpr=Selection;
DataSetFieldName=Selection }
...
Selection@1008 : 'Open,Closed,Open and Closed';

View file

@ -0,0 +1,13 @@
+++
title = "Readability"
weight = 980
tags = ["C/AL","Readability"]
categories = ["Best Practice"]
+++
## C/AL Coding Guidelines
## **Readability**
Generally, all readability rules are Microsoft style choices only. You can use them to keep consistency with the existing code.
Find the C/AL guidelines by expanding the menu in the left.

View file

@ -0,0 +1,24 @@
+++
title = "Begin as an 'After Word'"
weight = 230
tags = ["C/AL","Readability"]
categories = ["Best Practice"]
+++
When BEGIN follows THEN, ELSE, DO, it should be on the same line, preceded by one space character.
Bad code
```al
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN
BEGIN
...
END;
```
Good code
```
IF ICPartnerRefType = ICPartnerRefType::"Common Item No." THEN BEGIN
...
END;
```

Some files were not shown because too many files have changed in this diff Show more