<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Blog - Synergex</title>
	<atom:link href="https://www.synergex.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.synergex.com/blog/</link>
	<description>Where modernization meets proven systems</description>
	<lastBuildDate>Fri, 05 May 2023 12:49:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>

<image>
	<url>https://www.synergex.com/wp-content/uploads/2022/07/cropped-favicon-32x32.png</url>
	<title>Blog - Synergex</title>
	<link>https://www.synergex.com/blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">136209502</site>	<item>
		<title>Announcing SDI 2023.04.1150</title>
		<link>https://www.synergex.com/blog/2023/04/28/announcing-sdi-2023-04-1150/</link>
					<comments>https://www.synergex.com/blog/2023/04/28/announcing-sdi-2023-04-1150/#respond</comments>
		
		<dc:creator><![CDATA[Cindy Limburg]]></dc:creator>
		<pubDate>Fri, 28 Apr 2023 23:44:27 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Development Tools]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[SDI]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17269</guid>

					<description><![CDATA[<p>Our latest release of Synergy DBL Integration for Visual Studio (SDI) comes packed with a range of new features, improvements, and fixes to give you a<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/28/announcing-sdi-2023-04-1150/">Announcing SDI 2023.04.1150</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Our latest release of Synergy DBL Integration for Visual Studio (SDI) comes packed with a range of new features, improvements, and fixes to give you a better development experience. Changes include:</p>



<ul>
<li>Enhancements to general multi-threading and exception handling to provide better stability and performance of the build system</li>



<li>Changes for improved .NET stability, including better support for referencing C# projects without project GUIDs, and moving projects across solutions</li>



<li>Improved Telemetry, designed to proactively catch unexpected exceptions and make it easier for us to diagnose issues and thus provide more effective support. When you contact our Developer Support team, provide your Telemetry IDs by navigating to&nbsp;<strong>Tools &gt; Options &gt; Synergy DBL &gt; Advanced</strong> (see image below). These randomly generated IDs will enable us to look up the diagnostics for your specific session to troubleshoot the issue. (The telemetry data is anonymized.)</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" width="577" height="285" src="https://www.synergex.com/wp-content/uploads/2023/04/Picture1.png" alt="" class="wp-image-17270" srcset="https://www.synergex.com/wp-content/uploads/2023/04/Picture1.png 577w, https://www.synergex.com/wp-content/uploads/2023/04/Picture1-300x148.png 300w, https://www.synergex.com/wp-content/uploads/2023/04/Picture1-260x128.png 260w, https://www.synergex.com/wp-content/uploads/2023/04/Picture1-50x25.png 50w, https://www.synergex.com/wp-content/uploads/2023/04/Picture1-150x75.png 150w" sizes="(max-width: 577px) 100vw, 577px" /></figure>



<p>  </p>



<ul>
<li>Ability to load Common Properties and Environment Variables set from a selected project in the Solution Explorer into the Synergy VS Command Prompt (see image below)</li>
</ul>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="864" height="231" src="https://www.synergex.com/wp-content/uploads/2023/04/Picture2.png" alt="" class="wp-image-17271" srcset="https://www.synergex.com/wp-content/uploads/2023/04/Picture2.png 864w, https://www.synergex.com/wp-content/uploads/2023/04/Picture2-300x80.png 300w, https://www.synergex.com/wp-content/uploads/2023/04/Picture2-768x205.png 768w, https://www.synergex.com/wp-content/uploads/2023/04/Picture2-260x70.png 260w, https://www.synergex.com/wp-content/uploads/2023/04/Picture2-50x13.png 50w, https://www.synergex.com/wp-content/uploads/2023/04/Picture2-150x40.png 150w" sizes="(max-width: 864px) 100vw, 864px" /></figure>



<p>  </p>



<p>Note that Winforms and WPF projects are now deprecated (see image below). We&#8217;re no longer maintaining these project types with Microsoft updates. Winforms and WPF templates will be removed in a future SDI release, but the projects will continue to load until a Microsoft update fully breaks their support. We encourage you to turn on Telemetry to help us gain insights into whether these projects are still being actively used.</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="519" height="124" src="https://www.synergex.com/wp-content/uploads/2023/04/Picture3.png" alt="" class="wp-image-17272" srcset="https://www.synergex.com/wp-content/uploads/2023/04/Picture3.png 519w, https://www.synergex.com/wp-content/uploads/2023/04/Picture3-300x72.png 300w, https://www.synergex.com/wp-content/uploads/2023/04/Picture3-260x62.png 260w, https://www.synergex.com/wp-content/uploads/2023/04/Picture3-50x12.png 50w, https://www.synergex.com/wp-content/uploads/2023/04/Picture3-150x36.png 150w" sizes="(max-width: 519px) 100vw, 519px" /></figure>



<p>  </p>



<p>The improvements in this new release will provide you with a more seamless development experience. We encourage all users to upgrade. </p>



<p>Your feedback is crucial to us. Please share your thoughts on this release or anything SDI-related by emailing software development manager Tim Bauguess at <a href="mailto:tim.bauguess@synergex.com">tim.bauguess@synergex.com</a>. We would love to hear from you.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/28/announcing-sdi-2023-04-1150/">Announcing SDI 2023.04.1150</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/04/28/announcing-sdi-2023-04-1150/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17269</post-id>	</item>
		<item>
		<title>Synergex Acquired by FOG Software Group</title>
		<link>https://www.synergex.com/blog/2023/04/04/synergex-acquired-by-fog-software-group/</link>
					<comments>https://www.synergex.com/blog/2023/04/04/synergex-acquired-by-fog-software-group/#respond</comments>
		
		<dc:creator><![CDATA[William Mooney]]></dc:creator>
		<pubDate>Tue, 04 Apr 2023 18:37:51 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[President's Thoughts]]></category>
		<category><![CDATA[News]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17199</guid>

					<description><![CDATA[<p>I’m excited to announce that Synergex has been acquired by&#160;FOG Software Group, a division of&#160;Constellation Software Inc.&#160;After 45+ years of growing our business and helping our<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/04/synergex-acquired-by-fog-software-group/">Synergex Acquired by FOG Software Group</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I’m excited to <a href="https://velasoftwaregroup.com/synergex-acquired-by-fog-software-group/">announce</a> that Synergex has been acquired by&nbsp;<a href="https://www.fogsoftwaregroup.com/">FOG Software Group</a>, a division of&nbsp;<a href="https://www.csisoftware.com/">Constellation Software Inc.</a>&nbsp;After 45+ years of growing our business and helping our customers grow theirs, I and other Synergex shareholders felt it was time to turn over the reins to a new ownership team. And we couldn’t be more pleased with the acquisition opportunity that presented itself to us.&nbsp;</p>



<p>Constellation Software, Inc is a publicly traded Canadian company. Just as Synergex is committed to helping you preserve your legacy software, FOG/Constellation is committed to helping companies “preserve the legacy of their businesses”.&nbsp;They have an &#8220;Own For Life—Never Sell&#8221; philosophy.&nbsp;Their focus is on strengthening and growing businesses over the long-term.&nbsp;I’m confident that their expertise and resources will help ensure that Synergex will continue to thrive far into the future. Plus,&nbsp;we&#8217;ll have the opportunity to do bigger and more exciting things.&nbsp;</p>



<p>Although we’re now owned by FOG, we’re still Synergex. As a customer, you probably won’t notice many changes.&nbsp;FOG has a decentralized business model—their acquired companies typically run autonomously.&nbsp;I envision that Synergex will continue business as usual.&nbsp;The existing Synergex leadership team (including myself) will continue to operate and grow the company.&nbsp; Taking this leap and joining forces with FOG/Constellation has&nbsp;reinforced my vision that your Synergy applications will still be running—and thriving—in the year 2100 and beyond.&nbsp;If you have any questions about this change, please reach out to me, other leadership team members, or your account manager.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/04/synergex-acquired-by-fog-software-group/">Synergex Acquired by FOG Software Group</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/04/04/synergex-acquired-by-fog-software-group/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17199</post-id>	</item>
		<item>
		<title>Announcing SDI 2023.03.1080</title>
		<link>https://www.synergex.com/blog/2023/04/04/announcing-sdi-2023-03-1080/</link>
					<comments>https://www.synergex.com/blog/2023/04/04/announcing-sdi-2023-03-1080/#respond</comments>
		
		<dc:creator><![CDATA[Cindy Limburg]]></dc:creator>
		<pubDate>Tue, 04 Apr 2023 16:57:06 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Development Tools]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17192</guid>

					<description><![CDATA[<p>Synergy DBL Integration for Visual Studio (SDI) version 2023.03.1080 is now available for download in the Synergex Resource Center. This version includes several key enhancements, such<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/04/announcing-sdi-2023-03-1080/">Announcing SDI 2023.03.1080</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Synergy DBL Integration for Visual Studio (SDI) version 2023.03.1080 is now available for <a href="https://resources.synergex.com/SiteDownloadsSDI?version=2023.03.1080&amp;retUrl=#versions">download in the Synergex Resource Center</a>. This version includes several key enhancements, such as</p>



<ul>
<li>Additional multithreading stability improvements to reduce intermittent build, debug, and project load issues</li>



<li>Improved editor performance</li>



<li>IntelliSense and Build process enhancements, including support for spaces in names for folders with source files for Multiple Mainline projects</li>
</ul>



<p>View the&nbsp;<a href="https://resources.synergex.com/SiteReleaseNote?id=66c45df2-8a01-4d14-a1cc-0cc480fadd80">release notes</a><strong>&nbsp;</strong>for detailed information about the changes.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/04/announcing-sdi-2023-03-1080/">Announcing SDI 2023.03.1080</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/04/04/announcing-sdi-2023-03-1080/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17192</post-id>	</item>
		<item>
		<title>MSBuild CLI: A Gateway to Continuous Integration/Delivery</title>
		<link>https://www.synergex.com/blog/2023/04/03/msbuild-cli-a-gateway-to-continuous-integration-delivery/</link>
					<comments>https://www.synergex.com/blog/2023/04/03/msbuild-cli-a-gateway-to-continuous-integration-delivery/#respond</comments>
		
		<dc:creator><![CDATA[Arief Zein]]></dc:creator>
		<pubDate>Mon, 03 Apr 2023 23:22:29 +0000</pubDate>
				<category><![CDATA[Tech Article]]></category>
		<category><![CDATA[MSBuild CLI]]></category>
		<category><![CDATA[tech article]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17185</guid>

					<description><![CDATA[<p>The usual way to build software products during development is with an integrated development environment (IDE) such as Microsoft Visual Studio. Code changes are made in<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/03/msbuild-cli-a-gateway-to-continuous-integration-delivery/">MSBuild CLI: A Gateway to Continuous Integration/Delivery</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The usual way to build software products during development is with an integrated development environment (IDE) such as Microsoft Visual Studio. Code changes are made in the IDE, and the IDE has features for building and debugging code. It all happens in the same convenient environment, which is generally ideal during development. For building a shippable product, however, this approach is less than ideal in many cases, such as</p>



<ul>
<li>When the product needs to be part of a larger bundled set of products</li>



<li>When additional operations (secure signing, testing, staging, etc.) take place after the product is built</li>



<li>When the product is developed in a continuous integration/delivery (CI/CD) system, or when there is a goal to move to a CI/CD system</li>
</ul>



<p>In this article, we will focus on the last of these, building in a CI/CD system, which in simplified form looks something like this:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="601" height="131" src="https://www.synergex.com/wp-content/uploads/2023/04/Arief1.png" alt="" class="wp-image-17186" srcset="https://www.synergex.com/wp-content/uploads/2023/04/Arief1.png 601w, https://www.synergex.com/wp-content/uploads/2023/04/Arief1-300x65.png 300w, https://www.synergex.com/wp-content/uploads/2023/04/Arief1-260x57.png 260w, https://www.synergex.com/wp-content/uploads/2023/04/Arief1-50x11.png 50w, https://www.synergex.com/wp-content/uploads/2023/04/Arief1-150x33.png 150w" sizes="(max-width: 601px) 100vw, 601px" /></figure>



<p>Consider the Build step in this scenario. Building from the IDE is not ideal for CI/CD because in a fully automated environment, the result of a build should be immediately consumed by a testing infrastructure. Additionally, with CI/CD it is generally best for builds to occur in a separate environment—i.e., in a dedicated build environment. However, a build environment may not be able to launch the IDE due to machine settings, resources, licensing, or other environmental limitations. But if IDE builds are not ideal for CI/CD, how should the product be built in this situation?</p>



<p>Enter the MSBuild command-line interface (CLI).</p>



<p>MSBuild is Microsoft’s engine for building applications and libraries from Visual Studio projects and solutions. It is included in Visual Studio, and it runs behind the scenes when a build is invoked from Visual Studio. However, MSBuild is also available as a stand-alone product with a CLI that provides command-line equivalents for Visual Studio’s build functionality. Given a Visual Studio project or solution file, MSBuild can build the product from a single command. This solves several CI/CD-related issues:</p>



<ul>
<li>Because the stand-alone version of MSBuild is portable and can operate without Visual Studio, it simplifies requirements for machines dedicated to product builds. There is no need for Visual Studio licenses or extensive resources. This is especially useful for automatically provisioned machines in the cloud or in a pipeline environment.</li>



<li>There is a stand-alone 64-bit version of MSBuild, but only the 32-bit version is available from within Visual Studio. So if you need the 64-bit version for a build, the CLI is your only option.</li>



<li>The MSBuild CLI is automation friendly. It is much easier to automate a command-line build than to configure automation for a Visual Studio build.</li>



<li>A command-line build can easily be run as part of a larger automation process that builds multiple products and bundles them or prepares them to be consumed in subsequent automation processes (signing, validation, testing, etc.). The same applies when a product has other requirements, such as environment setup or dependencies that require other components to be built prior to the product build. A command-line build is also ideal if a product has pre- or post-build processing requirements.</li>
</ul>



<p>To illustrate how MSBuild CLI can be part of a larger CI/CD cycle, the following shows an expanded view of the Build step in the previous diagram:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="641" height="353" src="https://www.synergex.com/wp-content/uploads/2023/04/Arief2.png" alt="" class="wp-image-17187" srcset="https://www.synergex.com/wp-content/uploads/2023/04/Arief2.png 641w, https://www.synergex.com/wp-content/uploads/2023/04/Arief2-300x165.png 300w, https://www.synergex.com/wp-content/uploads/2023/04/Arief2-260x143.png 260w, https://www.synergex.com/wp-content/uploads/2023/04/Arief2-50x28.png 50w, https://www.synergex.com/wp-content/uploads/2023/04/Arief2-136x75.png 136w" sizes="(max-width: 641px) 100vw, 641px" /></figure>



<p>As you can see from this diagram, an IDE build would not fit well as a replacement for “MSBuild CLI build,” particularly in a fully automated environment.</p>



<p>We have been discussing why the MSBuild CLI should be used for product builds in a CI/CD environment. Now let’s examine how it is used. The stand-alone version of MSBuild comes as an executable that supports many build options through command-line switches. We will cover some of the most commonly used options below, but first let’s discuss how to install MSBuild as a stand-alone product. The stand-alone installer is available on the main download page for Visual Studio:</p>



<p><a href="https://visualstudio.microsoft.com/downloads/">https://visualstudio.microsoft.com/downloads/</a></p>



<p>Look for “Build Tools for Visual Studio 2022” on the page, or use the following direct link (subject to change):</p>



<p><a href="https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&amp;rel=17">https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&amp;rel=17</a></p>



<p>Once you have installed MSBuild, there will be an msbuild.exe file at the location you chose for the installation. This file is the MSBuild executable, which you’ll specify at the command line. In the most basic case, you can specify just “msbuild” followed by the project or solution file you want to build. For example:</p>



<pre class="wp-block-preformatted">msbuild MySolution.sln</pre>



<p>This command will build a solution named MySolution using the default configuration and platform for that solution. (The default is usually the “Debug” configuration and the “Any CPU” platform.) Again, this is the simplest form of MSBuild command. To exercise more control over a build, you can use command-line switches to specify build behaviors. The following are some commonly used switches. MSBuild supports ‘/’ or ‘-’ for switches, but for simplicity’s sake, we’ll use the ‘-’ form in the following.</p>



<ul>
<li>-property:<em>name</em>=<em>value</em> or -p:<em>name</em>=<em>value</em></li>
</ul>



<p>The -property (or -p) switch enables you to provide or override an MSBuild property. The most common use for this is to select a specific configuration or platform. For example, the following will produce a build based on the Release configuration and the x64 platform:</p>



<pre class="wp-block-preformatted">msbuild.exe -p:Configuration=Release -p:Platform=x64 MySolution.sln</pre>



<p>Of course, this switch is not limited to just configuration and platform. It can be used to specify any MSBuild property. A common use for -p when building Synergy projects is to specify the solution directory for the project, since some of the SDI tooling relies on the SolutionDir property setting when building a particular project instead of the solution. For example:</p>



<pre class="wp-block-preformatted">msbuild.exe ‑p:Configuration=Release ‑p:Platform=x64<br>‑p:SolutionDir=”C:\dev” MySynProj.synproj</pre>



<ul>
<li>-maxCpuCount<em>[</em>:<em>number]</em> or -m<em>[</em>:<em>number]</em></li>
</ul>



<p>The -maxCpuCount (or -m) switch specifies the maximum number of concurrent MSBuild processes allowed when building. If no number is specified, MSBuild uses the number of processors in the computer as this maximum. This feature allows for parallel builds of the projects in a solution, which results in faster overall build times.</p>



<ul>
<li>-target:<em>targets</em> or -t:<em>targets</em></li>
</ul>



<p>The -target (or -t) switch specifies MSBuild targets to run. If this switch is not specified, MSBuild will run the “Build” target for the specified project/solution. For example, if you want to rebuild the solution instead, use this switch to specify Rebuild. For example:</p>



<pre class="wp-block-preformatted">msbuild.exe -t:Rebuild MySolution.sln</pre>



<p>This switch also supports multiple targets in a semicolon delimited list. So, if you want to be explicit and specify a clean and then build (instead of specifying a rebuild), you would use a command like the following:</p>



<p>msbuild.exe -t:Clean;Rebuild MySolution.sln</p>



<ul>
<li>-verbosity:<em>level</em> or -v:<em>level</em></li>
</ul>



<p>The -verbosity (or -v) switch enables you to control the level of build information to be displayed or logged. Options are q<em>[</em>uiet<em>]</em>, m<em>[</em>inimal<em>]</em>, n<em>[</em>ormal<em>]</em> (which is the default), d<em>[</em>etailed<em>]</em>, and diag<em>[</em>nostic<em>]</em></p>



<ul>
<li>-graphBuild<em>[</em>:True or False<em>]</em> or -graph<em>[</em>:True or False<em>]</em></li>
</ul>



<p>When set to True, the -graphBuild (or -graph) switch causes MSBuild to construct a graph identifying project dependencies. MSBuild will also attempt to build project references prior to building the projects that reference them. (This is supported only for MSBuild 16 and higher.)</p>



<p>The full list of switches, along with more complete switch documentation is available at https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2022.</p>



<p>To recap, the MSBuild CLI is ideal for building products in a CI/CD system or in any fully automated system. The MSBuild CLI provides benefits unavailable with a Visual Studio build, including a more automation-friendly interface, fewer machine resource/licensing requirements (because it is a stand-alone tool), and easier set up for pre- and post-build requirements.</p>



<p>We hope this article encourages you to use the MSBuild CLI in your build environment and to adopt automation or CI/CD in your product development process. As always, we are excited to hear from you. If you have any questions or comments, contact Synergy/DE Developer Support or post in the Community area of the Synergex Resource Center. We will be happy to answer your queries!</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/04/03/msbuild-cli-a-gateway-to-continuous-integration-delivery/">MSBuild CLI: A Gateway to Continuous Integration/Delivery</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/04/03/msbuild-cli-a-gateway-to-continuous-integration-delivery/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17185</post-id>	</item>
		<item>
		<title>Training Others to Continue the Job</title>
		<link>https://www.synergex.com/blog/2023/03/29/training-others-to-continue-the-job/</link>
					<comments>https://www.synergex.com/blog/2023/03/29/training-others-to-continue-the-job/#respond</comments>
		
		<dc:creator><![CDATA[James Sahaj]]></dc:creator>
		<pubDate>Wed, 29 Mar 2023 18:34:58 +0000</pubDate>
				<category><![CDATA[Tech Article]]></category>
		<category><![CDATA[Hiring]]></category>
		<category><![CDATA[training]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17166</guid>

					<description><![CDATA[<p>You’ve worked on your software development job for 20 plus years and now you realize someone else is needed to grow your team and continue the<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/29/training-others-to-continue-the-job/">Training Others to Continue the Job</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You’ve worked on your software development job for 20 plus years and now you realize someone else is needed to grow your team and continue the legacy of the software. But how do you integrate this new person into your team in such a way as to pass on your years of knowledge, but keep it interesting and challenging to them so they stay?</p>



<h3 class="wp-block-heading">Hire Right and Welcome Them</h3>



<p>Much of the success in hiring depends on finding the right candidate. To increase your odds of success, give developer candidates a proficiency test to ensure a level of technical proficiency. During the interview, try to gauge the person’s interest and enthusiasm for the subject matter. Learn about their personality and decision-making processes. Will they fit with the culture of the company? Will they get along with you? Is there anything unusual that stood out about the candidate that you liked?</p>



<p>First impressions count! Before your new hire arrives, devise a welcome package for them. If you don’t have one, contact your Synergex account manager for examples. Most importantly, before they arrive, create a specific 90-day plan that details all the training, tasks, and goals for each 30-day interval. For each item, list the goal and the one or more tasks associated with that goal. In addition, include tasks they can do when there’s downtime, such as learning about the company itself. Training on languages, tools, and processes are all important. Consider also what training and classes they’ll need during each time interval, so that by the end of the 90 days they have a good base of understanding on which they can build additional knowledge. Developing a 90-day plan tells your new hire that you have thought about them, that they are important to you, and that you want them to succeed. After each 30-day interval, do a performance review to go over the expected completion of tasks. If you’re looking for a sample 90-day plan, contact your Synergex account manager and we’ll be happy to forward one of ours.</p>



<h3 class="wp-block-heading">Document the Unknown</h3>



<p>The base design of the current Synergy compilers was developed over the course of 15 years by a large group of developers. At Synergex, we typically document software with extensive comments. But throwing someone into a code base, even with extensive comments, is not fair. You may have old requirements documents and thousands of pages of old design documents with pretty diagrams, but, if they’re not already out of date, would you really want to sit down read that volume of documents? Please don’t bore your understudy.</p>



<p>You understand years of decisions and designs about that software. You know its strengths and weaknesses—so share these in a concise, readable form by developing a “My Software 101” document that gives bite-size descriptions of each important individual design concept in your software. Describe these in common, easy-to-understand terms so that a person without your level of experience can grasp them. For each design concept, ask yourself: What is its purpose? Why is it important? How does it fit in with the whole design? Add detail as necessary, but don’t get into the weeds—stay focused on the higher-level concepts. For example, in our 101 document on the Synergy compilers, we broke the design down by stages of compilation first, and then went into more detail on the main concepts in each stage.</p>



<h3 class="wp-block-heading">Code Reviews with a Purpose</h3>



<p>Let the new hire read the 101 document and ask questions. These questions will guide you to improve the document, so take the opportunity to do so.</p>



<p>Using the 101 document you developed, on a frequent basis (we do daily), review the code associated with a single bite-sized design. Before COVID-19, we sat side-by-side to review code, but we’ve found that remote presentation over Microsoft Teams also works well. Start with the most basic building blocks of the design concepts and work your way into those that are more complex and that build upon others. Explain how the code implements the design and what is important to understand about the code for a particular design.</p>



<h3 class="wp-block-heading">Small Challenges</h3>



<p>At some point, you’ll want to give your new hire some small challenges, likely during the last interval of the 90-day period. It’s best if you can find a bug related to some section of code you’ve already reviewed with them. Find something you think they should be able to solve on their own given their training up to that point, and which isn’t time critical.</p>



<p>Once you assign the challenge…step away! Let them try to solve it on their own and have them contact you when it’s done. It’s likely their solution may not be exactly what you would have done. That’s OK. Review the code to see whether it meets your coding standards, is maintainable, and solves the problem. If there are improvements that could be made or a different approach that could be taken, ask questions about their solution to guide them toward these changes. The important part isn’t to tell them how you would solve it or exactly what they need to do, but to guide them in how to think about the problem, so they can come up with the solution on their own.</p>



<p>As your new hire completes these small challenges, you may find additional design concepts that you hadn’t thought of initially, or things that you thought were too detailed, when creating the 101 document. As you find these, add them to the 101 document and do a review of them along with the associated code.</p>



<h3 class="wp-block-heading">The Deep End</h3>



<p>After your new hire completes the 101 discussions and reviews, along with a number of smaller challenges, you’ll want to give them something much more challenging. Maybe it’s a mini-project they can do on their own or a project where they’ll need to work together with other developers. Whatever it is, make sure the tasks and expectations are well-defined and understood. Set a schedule for the completion of tasks and let them know you are available to answer questions. Again, as before, use leading questions to develop their ability to solve problems on their own.</p>



<p>Throughout the project, ensure you touch base with them at least once a day to find out what they worked on yesterday and what they plan on doing today. Not only will you get a sense of how the larger project is going, but it’s a good time for them to ask any additional questions of you and promote the team dynamic.</p>



<h3 class="wp-block-heading">The Result</h3>



<p>The goal at the end of it all is to have an efficient, knowledgeable developer who understands the important design concepts used in your software and can think on their own of solutions to problems they encounter. Much of the success of it does depend on the talent and ability of the new hire, but you also play an important role in that person’s success by mentoring, guiding, and encouraging them along the way. By planning from the start, you can make this a reality for your team and your company.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/29/training-others-to-continue-the-job/">Training Others to Continue the Job</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/03/29/training-others-to-continue-the-job/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17166</post-id>	</item>
		<item>
		<title>Why Legacy Systems Remind Me of That Song “I’m Still Standing”</title>
		<link>https://www.synergex.com/blog/2023/03/10/why-legacy-systems-remind-me-of-that-song-im-still-standing/</link>
					<comments>https://www.synergex.com/blog/2023/03/10/why-legacy-systems-remind-me-of-that-song-im-still-standing/#respond</comments>
		
		<dc:creator><![CDATA[William Mooney]]></dc:creator>
		<pubDate>Fri, 10 Mar 2023 22:07:19 +0000</pubDate>
				<category><![CDATA[President's Thoughts]]></category>
		<category><![CDATA[legacy systems]]></category>
		<category><![CDATA[modernization]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17121</guid>

					<description><![CDATA[<p>Whenever I hear that 1980s song “I’m Still Standing” by Elton John, I like to think it’s about the rock-solid dependability of legacy systems. Back there<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/10/why-legacy-systems-remind-me-of-that-song-im-still-standing/">Why Legacy Systems Remind Me of That Song “I’m Still Standing”</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Whenever I hear that 1980s song “I’m Still Standing” by Elton John, I like to think it’s about the rock-solid dependability of legacy systems. Back there in the shadows of the machine room, the legacy system runs smoothly year after year—for decades—providing the stability that allows an enterprise to grow and flourish. Like the song, it’s still standing after all this time, better than it ever did. But that stability is threatened when the organization starts down the road of leaving a mature, working system in the quest for something new. Under the banner of modernization or digital transformation (often initiated by a new CxO), an organization will sometimes abandon the legacy code that has faithfully supported its line of business operations in the belief that they can replicate rock solid legacy code with a new application. The results can be disastrous.</p>



<p>Given enough time and enough money, it <em>may</em> be possible to capture the decades of nuanced business knowledge, best practices, and mission critical logic that have been crafted into your legacy (aka proven) enterprise code. However, over many years of working with enterprise IT organizations and their CxOs, I’ve seen very few of these projects completed, and I’m not sure if any of those would really be considered “successful.”</p>



<p>In the best-case scenario, the organization recognizes that they’re going down the wrong path early in the effort (often when new CxO #2 enters the picture), and they return to their trusted legacy code. They discover the logic of moving to a modern solution <em>with</em> the code that has kept their business running for decades. Add a modern UI/UX? Yes! Integrate with other systems inside or outside your business? Sure! Go to the cloud? Not a problem! The trick is to add whatever front-end or new functionality you want—while keeping the proven legacy code that runs your operations.</p>



<p>In the worst-case scenario, they continue to run <em>away</em> from their legacy stability as they pour money and time—many years’ worth—into attempting to recreate something that was never broken. The legacy code that keeps businesses thriving has been crafted over the years to the point where just understanding all that it does—and why—would be an extremely challenging, multi-year project in itself. And heaven help a development team that sets out to replace a legacy system <em>without</em> knowing everything that it does. I believe this is the primary reason these projects fail: they require much more time and money to replace functions the project team never fully understood. (For more on this, see my blog post titled <a href="https://www.synergex.com/blog/2021/09/16/when-it-comes-to-legacy-systems-its-hip-to-be-square/">“When It Comes to Legacy Systems, It’s Hip to Be Square.”</a>)</p>



<p><strong>$500 Million Trainwrecks</strong></p>



<p>I’m not the only one who has seen the trainwrecks that can happen when perfectly good legacy code is tossed out simply because it’s perceived as being old. (Age discrimination for applications?) Henrico Dolfing, who spoke at our 2022 DevPartner Conference, maintains an entire <a href="https://www.henricodolfing.com/">blog</a> on this topic. Or you can find your own: Google “SAP disasters” or “ERP project fails” or whatever similar phrase comes to mind.</p>



<p>A few years ago, <em>The Register</em> published an <a href="https://www.theregister.com/2019/12/12/erp_disaster_zone_the_mostly_costly_failures_of_the_past_decade/">article</a> headlined “ERP Disaster Zone: The Most Costly Failures of the Last Decade.” Just one example from their collection: A German supermarket chain spent 500 million euros—about half a <em>billion</em> dollars—to replace its in-house legacy merchandise management system . . . before terminating the project. To the company’s credit, they finally pulled the plug at the half-billion-dollar mark, while others remain trapped by an “in for a dime, in for a dollar” mentality of hoping that success will be somewhere down the road, without realizing just how long and expensive such a road can be. But wow! Half a billion? That’s a lot of money down the drain. And, had the plug not been pulled, it could have been even worse.</p>



<p><strong>The Costs Keep Coming</strong></p>



<p>In my many years of experience, I’ve seen that organizations attempting to replicate the functionality of a legacy application in a new application not only spend significantly more years and many more millions of dollars than initially planned, but they also end up with an application that differs greatly from the plan. As reality beats away at their original aspirations, the glowing vision slips into survival mode: What can we do to keep things at least business functional?</p>



<p>Even if and when the development efforts are declared complete, the costs keep coming.</p>



<p>A legacy system generally has a low base for operational costs. You are dealing with a known quantity. Even a system’s shortcomings are known and can be addressed. But with a new application, you are continually dealing with unknowns, as shortcomings arise because (despite all the time and money invested) the new application doesn’t capture everything that was crafted into the original system.</p>



<p>This means operational costs are higher, and the work-around development costs never really end.</p>



<p>A key question for these “finished” projects is, considering all the costs during the project and the additional costs now required to develop/maintain/support the new system, does the ROI really pan out? Will the new system have enough benefits to warrant all that extra time and money? Especially when you could have moved forward and met your modernization needs at a much lower cost and much less turmoil with your proven legacy code?</p>



<p>One former customer offered a candid reflection on the question of ROI based on his company’s experience. He noted, “Moving to the new ERP system took seven years instead of the planned three; the budget increased by 500%; and we still don’t have the stability or speed of our legacy system.” (For more details about lessons he learned on that project and others, I suggest you read the <a href="https://www.synergex.com/wp-content/uploads/2023/03/Replacing-Legacy-Systems-Lessons-Learned-v2.pdf">case study</a>.)</p>



<p><strong>Invest in (and Move Forward with) What You Have</strong></p>



<p>From my experience, here’s how the typical scenario plays out: The legacy (again, the <em>proven</em>) enterprise application that was developed and refined over the years has been fine-tuned and tested and is a rock-solid product servicing the needs of the company. Any issues are known. These may include a desire to update to new hardware or operating environments, move to the cloud, enhance the user interface/user experience, improve data access, provide web access, find skilled resources to continue development and maintenance, and so on.</p>



<p>Yet most companies do nothing to address these known issues—essentially kicking the can down the road. The reasons vary: inertia, thinking that nothing can be done to improve the situation, no one championing a way forward, an “out of sight, out of mind, if it ain’t broke, don’t fix it” mindset, no budget allocation for enhancements, lack of domain knowledge because the original creators and developers have moved on, technology influencers looking for the next shiny toy to add to their skill list or thinking they can save the company money by reducing license and other fees with “their” solution, and many more.</p>



<p>Then one day, the company decides changes are needed. A big budget is allocated, a vision of a perfect new system to replace the old one is presented, project schedules are established, and the project moves forward. Interestingly, these projects used to be projected for two years, and it was fairly easy for companies to pull the plug when they went awry. These days, initial projections for such projects are typically three to four years, though in reality they take seven to ten. With that larger investment, companies have a harder time pulling out when they realize they’re on the wrong course. They feel there’s no turning back, so they throw even more time and money at the project and continue down an unfortunate path.</p>



<p>A new CxO might go into this type of project thinking this predicament could never happen to their company, believing they are doing it differently, but the same outcome occurs time after time. The success rate of such replacement projects is consistently very low.</p>



<p>My advice: Rather than spending a massive amount of time and money creating something new, simply enable your existing legacy system to meet your needs—whether it’s adding a new UI, moving to cloud-based infrastructure, generating user-friendly analytics, or whatever other advancement you’d like. You can be a hero. It will look great on your annual review: Saved the company $500 million and 10 years of misery.</p>



<p><strong>Three Questions to Ask</strong></p>



<p>In an ideal world, the following questions would be thoroughly researched and objectively answered before anyone considers heading down a replacement path:</p>



<ol type="1">
<li>What are the real problems we are trying to solve?</li>



<li>Can we solve these problems using our current system?</li>



<li>What are the actual costs of alternative choices (money, time, stability, loss of functionality, distractions, the duplicated effort required to continue maintaining an existing system while developing the new one, etc.)?</li>
</ol>



<p>With almost any legacy system, vendors are available with tools and resources to help achieve the desired results at a fraction of the cost and with a high degree of success. Add a new UI/UX, put your application in the cloud, give data access to executives, train the next generation of developers, have managed services to do the work for you—companies (including many Synergex customers) are doing these things and much more with their legacy systems.</p>



<p>Wouldn’t it be a relief <em>not</em> to have to replicate decades of business intelligence? Knowing that you have it in place and can focus your efforts on extending that critical logic instead of replacing it, you’ll have the best opportunity for a successful modernization project, one that requires a lot less money and provides a superior outcome. Synergex’s investment in our tools and consulting services has a proven track record of ensuring success. In our 47 years, we have never wavered from our primary focus of empowering you to leverage your initial investment in perpetuity. Or as I like to say, your legacy-based applications will still be standing—and thriving—in the year 2100 and beyond.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/10/why-legacy-systems-remind-me-of-that-song-im-still-standing/">Why Legacy Systems Remind Me of That Song “I’m Still Standing”</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/03/10/why-legacy-systems-remind-me-of-that-song-im-still-standing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17121</post-id>	</item>
		<item>
		<title>Announcing SDI 2023.3.1019</title>
		<link>https://www.synergex.com/blog/2023/03/03/announcing-sdi-2023-3-1019/</link>
					<comments>https://www.synergex.com/blog/2023/03/03/announcing-sdi-2023-3-1019/#respond</comments>
		
		<dc:creator><![CDATA[Cindy Limburg]]></dc:creator>
		<pubDate>Fri, 03 Mar 2023 19:27:26 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Development Tools]]></category>
		<category><![CDATA[Release Notifications]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17110</guid>

					<description><![CDATA[<p>A new release of Synergy DBL Integration for Visual Studio (SDI) is now available for download in the Synergex Resource Center. This release includes several key<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/03/announcing-sdi-2023-3-1019/">Announcing SDI 2023.3.1019</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>A new release of Synergy DBL Integration for Visual Studio (SDI) is now available for <a href="https://resources.synergex.com/SiteDownloadsSDI?version=2023.03.1019&amp;retUrl=#versions"><strong>download in the Synergex Resource Center</strong></a>.</p>



<p>This release includes several key enhancements and fixes to improve your developer experience, including</p>



<ul>
<li>Multithreading updates, which improve the stability of the product, reducing intermittent build, debug, and project load issues that some users have experienced, particularly around .NET projects.</li>



<li>Fixes for unexpected build task failures, including DBLT and DBPT; these improve error list window reporting to make it easier for you to quickly identify and fix these issues.</li>



<li>General IntelliSense improvements to provide you with more accurate and useful suggestions as you code.</li>



<li>A variety of compiler updates to support new .NET language features and improve compiler quality.</li>
</ul>



<p>More multithreading enhancements are planned for upcoming releases. We believe our focus in this area will make a significant difference to your developer experience, providing you with a smoother, more efficient process. View the&nbsp;<strong><a href="https://resources.synergex.com/SiteReleaseNote?id=66c45df2-8a01-4d14-a1cc-0cc480fadd80">release notes</a> </strong>for detailed information about the changes in this release.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/03/announcing-sdi-2023-3-1019/">Announcing SDI 2023.3.1019</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/03/03/announcing-sdi-2023-3-1019/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17110</post-id>	</item>
		<item>
		<title>Announcing Synergy/DE 12.1.1.3287</title>
		<link>https://www.synergex.com/blog/2023/03/01/announcing-synergy-de-12-1-1-3287/</link>
					<comments>https://www.synergex.com/blog/2023/03/01/announcing-synergy-de-12-1-1-3287/#respond</comments>
		
		<dc:creator><![CDATA[Cindy Limburg]]></dc:creator>
		<pubDate>Wed, 01 Mar 2023 23:37:01 +0000</pubDate>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Release Notifications]]></category>
		<category><![CDATA[Synergy/DE]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17106</guid>

					<description><![CDATA[<p>A new update to our Synergy/DE 12.1 long-term support (LTS) release is now available for download in the Synergex Resource Center. Synergy/DE 12.1.1.3287 is a quality<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/01/announcing-synergy-de-12-1-1-3287/">Announcing Synergy/DE 12.1.1.3287</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>A new update to our Synergy/DE 12.1 long-term support (LTS) release is now available for <a href="https://resources.synergex.com/SiteDownloads?homeURL=%2Fapex%2FSiteProducts">download</a> in the Synergex Resource Center. Synergy/DE 12.1.1.3287 is a quality release that includes improvements across the product set. It’s available for Windows (32- &amp; 64-bit), IBM AIX (32- &amp; 64-bit), Linux (32- &amp; 64-bit), OpenVMS Alpha and OpenVMS IA64.</p>



<p>New downloads for the <a href="https://resources.synergex.com/SiteDownloadsLUP">REV11 Licensing Upgrade Package</a> and <a href="https://resources.synergex.com/SiteDownloadsPlatform?os=Windows&amp;version=12.1.1.3287">Local Synergy/DE Product Documentation</a> are also available with this release. View the&nbsp;<strong>release notes</strong>&nbsp;at the bottom of the <a href="https://resources.synergex.com/SiteDownloads?homeURL=%2Fapex%2FSiteProducts">Downloads</a> page for detailed information about the changes.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2023/03/01/announcing-synergy-de-12-1-1-3287/">Announcing Synergy/DE 12.1.1.3287</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2023/03/01/announcing-synergy-de-12-1-1-3287/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17106</post-id>	</item>
		<item>
		<title>YAML Your Way to Rapid Deployment</title>
		<link>https://www.synergex.com/blog/2022/12/19/yaml-your-way-to-rapid-deployment/</link>
					<comments>https://www.synergex.com/blog/2022/12/19/yaml-your-way-to-rapid-deployment/#respond</comments>
		
		<dc:creator><![CDATA[Sonny Wong]]></dc:creator>
		<pubDate>Mon, 19 Dec 2022 16:25:00 +0000</pubDate>
				<category><![CDATA[Tech Article]]></category>
		<category><![CDATA[tech article]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17073</guid>

					<description><![CDATA[<p>As the expectation for fast-paced product releases grows throughout the software industry, more and more software development organizations are adopting DevOps practices and cloud-based tools to<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2022/12/19/yaml-your-way-to-rapid-deployment/">YAML Your Way to Rapid Deployment</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As the expectation for fast-paced product releases grows throughout the software industry, more and more software development organizations are adopting DevOps practices and cloud-based tools to pick up the pace. One of the key DevOps techniques that makes faster release cadences possible is CI/CD, which is an acronym for “continuous integration” and either “continuous delivery” or “continuous deployment.” CI/CD encompasses practices that automate builds, testing, and deployment as a continuous process, enabling issues to surface quickly while harnessing the speed of automation. This automation generally takes place using cloud-based tools, and at Synergex we’ve adopted CI/CD via Azure pipelines, which automate these operations in Azure DevOps. Azure pipelines are relatively easy to set up, and when defined using the YAML language, they can be very flexible and can accommodate complex CI/CD scenarios.</p>



<p>When Azure pipelines were first introduced, developers created and configured these pipelines exclusively via GUI screens that presented CI/CD operations as GUI options. Here’s an example of a GUI screen that enables developers to choose operations for an Azure pipeline:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="624" height="393" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny1.png" alt="" class="wp-image-17075" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny1.png 624w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny1-300x189.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny1-232x146.png 232w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny1-50x31.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny1-119x75.png 119w" sizes="(max-width: 624px) 100vw, 624px" /></figure>



<p>This approach can work for basic tasks, and developers can still use these GUI screens to configure Azure pipelines. But these GUI selections are not always interpreted correctly when pipelines are generated, so resulting pipelines do not always work as expected. Fortunately, as mentioned above, you can also set up Azure pipelines using YAML, which is a data serialization language (like JSON). Depending on whom you ask, YAML stands for either “Yet Another Markup Language” (its original meaning) or “YAML Ain’t Markup Language”. In any case, for some time now Azure DevOps has enabled developers to define pipelines by coding them in YAML, and Microsoft now recommends this method. This not only eliminates issues resulting from imperfect pipeline generation from GUI screen selections (one less variable when a pipeline fails), but it gives developers more control over pipeline operations and flow.</p>



<p>In this article, we’ll briefly look at the basic steps for setting up a simple YAML pipeline that builds, tests, and deploys. But first, let’s take a closer look at CI/CD. In simple terms, continuous integration (CI) is the automation of builds and testing every time a developer commits a change to version control. And continuous delivery or deployment (CD) is the automated deployment of built software to a test or production environment. CI/CD processes can be complicated, and that’s where YAML comes in. YAML enables you to code complex operations (e.g., multiple CI/CD workflows) in a single file, so that they all operate as one contiguous workflow, one pipeline. For example, once a build is completed and tested, a multi-stage YAML pipeline could then deploy the build to different environments for further testing before finally deploying to production. The figure below shows Azure DevOps reporting on the build and deployment stages of a simple pipeline we have for an internal service.</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="539" height="239" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny2.png" alt="" class="wp-image-17076" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny2.png 539w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny2-300x133.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny2-260x115.png 260w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny2-50x22.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny2-150x67.png 150w" sizes="(max-width: 539px) 100vw, 539px" /></figure>



<p><strong>Before you start…</strong></p>



<p>There are some prerequisites for creating Azure pipelines. You must have access to Azure DevOps with permissions to create pipelines, and you must have a deployment environment (e.g., a web service) for your pipeline to deploy builds to. Additionally, the source code for the software you are developing must be stored in a version control system. In the example pipeline we’ll look at in this article, we’ll select a Git repository in Azure, but you can use some other version control system such as Bitbucket or Subversion.</p>



<p><strong>Creating the base YAML for a pipeline</strong></p>



<p>Now let’s see how YAML is used by creating a simple YAML pipeline. We’ll start by instructing DevOps to set up a basic YAML file that will be the starting point for our pipeline and will be added as a .yml file to the repository we’ll select in this process.</p>



<p>After signing into Azure DevOps, we’ll select Pipelines in the navigation area, select the Pipelines option under that, and then click the “New pipeline” button in the upper-right of the Pipelines area.</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="659" height="183" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny3.png" alt="" class="wp-image-17077" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny3.png 659w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny3-300x83.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny3-260x72.png 260w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny3-50x14.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny3-150x42.png 150w" sizes="(max-width: 659px) 100vw, 659px" /></figure>



<p>Next, we’ll specify where the source code is coming from. For this example, we’ll use the “Azure Repos Git” option (the first option shown in the following screen capture), and then we’ll select the repository that the pipeline will be generated for. (Azure DevOps prompts you for this once you’ve selected the version control source.)</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="490" height="397" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny4.png" alt="" class="wp-image-17078" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny4.png 490w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny4-300x243.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny4-180x146.png 180w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny4-50x41.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny4-93x75.png 93w" sizes="(max-width: 490px) 100vw, 490px" /></figure>



<p>We’ll then select the type of project we want to use the pipeline for. The example pipeline we’re setting up here will deploy to an Azure web service, so we’ll select ASP.NET:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="489" height="493" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny5.png" alt="" class="wp-image-17079" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny5.png 489w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-298x300.png 298w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-150x150.png 150w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-145x146.png 145w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-50x50.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-74x75.png 74w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-85x85.png 85w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny5-80x80.png 80w" sizes="(max-width: 489px) 100vw, 489px" /></figure>



<p>At this point, DevOps creates a basic YAML file from the choices we’ve made, and it displays that file in Azure DevOps:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="624" height="560" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny6.png" alt="" class="wp-image-17080" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny6.png 624w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny6-300x269.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny6-163x146.png 163w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny6-50x45.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny6-84x75.png 84w" sizes="(max-width: 624px) 100vw, 624px" /></figure>



<p><strong>Understanding YAML basics</strong></p>



<p>Now we finally see what a YAML file looks like. We can add more code to this file to define pipeline operations, but first let’s break this starter code down a bit and see what it does by looking at some of the keywords it uses. For more information on YAML, including YAML keywords, and for information on Azure pipelines in general, see&nbsp;<a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops"><strong>Microsoft’s documentation on Azure Pipelines</strong></a>.</p>



<p><strong>trigger:</strong><br>The&nbsp;<strong>trigger&nbsp;</strong>keyword at the beginning of the file causes the pipeline to run when a specified event takes place. In this case, the pipeline will run whenever an update is pushed to the specified repository branch, which is “main” in the code shown above.</p>



<p><strong>pool:</strong><br>The&nbsp;<strong>pool&nbsp;</strong>option specifies the agent that will be used to run pipeline operations. For the base pipeline we just set up, it defines the specs for the virtual machine image, ‘windows – latest’, that will be used to build the project. As of this writing, this is a Windows Server 2022 image with Visual Studio 2022. Other options include Ubuntu and MacOS virtual machines.&nbsp;</p>



<p><strong>variables:</strong><br>The&nbsp;<strong>variables&nbsp;</strong>keyword enables you to set system variables or define your own variables at the beginning of a YAML pipeline file. These variables are treated as environment variables when the pipeline is triggered. Most variables are defined using the format&nbsp;<strong>solution:&nbsp;‘**/*.sln’</strong>. And once they are defined, you can generally use the following format to reference them elsewhere in the pipeline: $(solution).</p>



<p><strong>stage:</strong><br>Stages, which are defined by the&nbsp;<strong>stage&nbsp;</strong>keyword, delineate the larger divisions in a pipeline (and come after the stages keyword). For example, the following code is for a build stage. It is important to place tasks for a stage under the job section for that stage (e.g.,&nbsp;<strong>job:&nbsp;Build</strong>) to instruct Azure DevOps that they belong only to that stage.</p>



<p></p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="652" height="199" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny7-1.png" alt="" class="wp-image-17081" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny7-1.png 652w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny7-1-300x92.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny7-1-260x79.png 260w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny7-1-50x15.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny7-1-150x46.png 150w" sizes="(max-width: 652px) 100vw, 652px" /></figure>



<p>Likewise, we can add a deployment stage:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="250" height="97" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny8-1.png" alt="" class="wp-image-17082" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny8-1.png 250w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny8-1-50x19.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny8-1-150x58.png 150w" sizes="(max-width: 250px) 100vw, 250px" /></figure>



<p><strong>task:</strong><br>Tasks define what the pipeline should do. The&nbsp;<strong>steps&nbsp;</strong>keyword must precede the&nbsp;<strong>task&nbsp;</strong>keyword, or you’ll get an invalid YAML structure error. You can add all sorts of tasks, but a minimal pipeline needs only build and deploy tasks.</p>



<p>When setting up tasks, keep in mind that Azure DevOps includes an “assistant” that can make adding tasks much easier. To open the assistant, click “Show assistant,” which is on the upper right of the editing pane when you’re editing a YAML file.</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="606" height="145" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny9-1.png" alt="" class="wp-image-17083" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny9-1.png 606w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny9-1-300x72.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny9-1-260x62.png 260w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny9-1-50x12.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny9-1-150x36.png 150w" sizes="(max-width: 606px) 100vw, 606px" /></figure>



<p>For example, we can use this assistant to set up a NuGet task that will restore NuGet packages before building the solution. To do this, in the YAML editor we’ll move to the location right before the build task, open the assistant, scroll down the task list, and select the NuGet option:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="352" height="226" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny10-1.png" alt="" class="wp-image-17084" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny10-1.png 352w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny10-1-300x193.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny10-1-227x146.png 227w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny10-1-50x32.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny10-1-117x75.png 117w" sizes="(max-width: 352px) 100vw, 352px" /></figure>



<p>We’ll then supply information that the assistant prompts us for, and we’ll click Add:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="262" height="432" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny11-2.png" alt="" class="wp-image-17085" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny11-2.png 262w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny11-2-182x300.png 182w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny11-2-89x146.png 89w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny11-2-30x50.png 30w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny11-2-45x75.png 45w" sizes="(max-width: 262px) 100vw, 262px" /></figure>



<p>The assistant will generate code like the following, which we can modify, remove, etc., in the code editor:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="255" height="81" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny12-1.png" alt="" class="wp-image-17086" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny12-1.png 255w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny12-1-50x16.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny12-1-150x48.png 150w" sizes="(max-width: 255px) 100vw, 255px" /></figure>



<p>If you are unfamiliar with writing YAML, using the assistant is a great way to get started adding tasks.</p>



<p><strong>displayName:</strong><br>The&nbsp;<strong>displayName&nbsp;</strong>keyword is used to specify the name that will be displayed for a task when the pipeline runs it. For example, in the following screen capture of a DevOps status window, the “Use .NET Core sdk 2.2x” label was not the original label for the task it represents. This label was added with a&nbsp;<strong>displayName&nbsp;</strong>setting.</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="320" height="117" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny13-1.png" alt="" class="wp-image-17087" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny13-1.png 320w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny13-1-300x110.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny13-1-260x95.png 260w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny13-1-50x18.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny13-1-150x55.png 150w" sizes="(max-width: 320px) 100vw, 320px" /></figure>



<p><strong>inputs:</strong><br>Inputs are the options that you can modify when adding a task. For example, the NuGet restore task we defined above takes required inputs for&nbsp;<strong>command</strong>,&nbsp;<strong>restoreSolution</strong>, and&nbsp;<strong>feedsToUse</strong>, which the assistant added for us.</p>



<p><strong>Setting up deployment</strong></p>



<p>The last part of our example pipeline will deploy the built app to an Azure web service. But before the pipeline can deploy, the Build stage needs to publish build artifacts for the pipeline. The following task lets the pipeline know where to get the files that are ready for deployment. This task and the other tasks we’re about to look at can also be created using the task assistant.</p>



<pre class="wp-block-code"><code>- task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'drop'
        publishLocation: 'Container'
</code></pre>



<p>Then, in the Deploy stage, we need to download the build artifact to deploy:</p>



<pre class="wp-block-code"><code>- task: DownloadBuildArtifacts@1
      inputs:
        buildType: 'current'
        downloadType: 'single'
        downloadPath: '$(System.ArtifactsDirectory)'
        artifactName: 'drop'
</code></pre>



<p>Additionally, when deploying to an Azure app service, we must add a task to verify and authorize the Azure subscription and select the name of the app service the build will be deployed to. For example:</p>



<pre class="wp-block-code"><code>- task: AzureRmWebAppDeployment@4
      inputs:
        ConnectionType: 'AzureRM'
        azureSubscription: 'Visual Studio Enterprise Subscription – MPN(XXXXXXX)'
        appType: 'webApp'
        WebAppName: 'Some-Staging-Area'
        deployToSlotOrASE: true
        ResourceGroupName: 'Some-Staging-Area
        SlotName: 'staging'
        packageForLinux: '$(Build.ArtifactStagingDirectory)/**/*.zip'
</code></pre>



<p>In this example,&nbsp;<strong>packageForLinux</strong>&nbsp;is set to&nbsp;<strong>$(Build.ArtifactStagingDirectory)/**/*.zip</strong>&nbsp;because this is where the build artifact will be published in the last step of the Build stage. (The&nbsp;<strong>packageForLinux</strong>&nbsp;option is an alias for the &nbsp;<strong>Package &nbsp;</strong>keyword, and in the task assistant this is created using the “Package or folder” option.)</p>



<p><strong>The completed pipeline</strong></p>



<p>Now that we have a better sense of how YAML works and how we can use YAML to set up a pipeline, here’s a completed version of the pipeline we started above:</p>



<pre class="wp-block-code"><code>trigger:
- main

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

stages:
- stage: Build
  jobs:
  - job: Build
    steps:
    - task: NuGetCommand@2
      inputs:
        command: 'restore'
        restoreSolution: '**/*.sln'
        feedsToUse: 'select'

    - task: PowerShell@2
      displayName: Start CosmosDB Emulator
      inputs:
        targetType: 'inline'
        script: |
          Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator"
            Start-CosmosDbEmulator

    - task: UseDotNet@2
      displayName: 'Use .NET Core sdk 2.2.x'
      inputs:
        version: 2.2.x

    - task: NuGetToolInstaller@1

    - task: NuGetCommand@2
      inputs:
        command: 'restore'
        restoreSolution: '$(solution)'
        feedsToUse: 'select'

    - task: VSBuild@1
      displayName: 'Build solution'
      inputs:
        solution: '$(solution)'
        msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(Build.ArtifactStagingDirectory)\\"'
        platform: '$(BuildPlatform)'
        configuration: '$(BuildConfiguration)'
        clean: true

    - task: VSTest@2
      displayName: 'Run Tests'
      inputs:
        testSelector: 'testAssemblies'
        testAssemblyVer2: |
          **\$(BuildConfiguration)\*Test*.dll
          **\$(BuildConfiguration)\**\*Test*.dll
          !**\*Microsoft.VisualStudio.TestPlatform*
          !**\obj\**
        searchFolder: '$(System.DefaultWorkingDirectory)'
        codeCoverageEnabled: true
        platform: '$(buildPlatform)'
        configuration: '$(buildConfiguration)'

    - task: PublishSymbols@1
      displayName: 'Publish symbols path'
      inputs:
        SearchPattern: '**\bin\**\*.pdb'
      continueOnError: true

    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'drop'
        publishLocation: 'Container'

- stage: Deploy
  jobs:
  - job: Deploy
    steps:
    - task: DownloadBuildArtifacts@1
      inputs:
        buildType: 'current'
        downloadType: 'single'
        downloadPath: '$(System.ArtifactsDirectory)'
        artifactName: 'drop'
    - task: AzureRmWebAppDeployment@4
      inputs:
        ConnectionType: 'AzureRM'
        azureSubscription: 'Visual Studio Enterprise Subscription – MPN(XXXXXXX)'
        appType: 'webApp'
        WebAppName: 'Some-Staging-Area'
        deployToSlotOrASE: true
        ResourceGroupName: 'Some-Staging-Area
        SlotName: 'staging'
        packageForLinux: '$(Build.ArtifactStagingDirectory)/**/*.zip'
</code></pre>



<p>When this pipeline is triggered, it will build, run tests, and deploy:</p>



<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="539" height="239" src="https://www.synergex.com/wp-content/uploads/2023/02/Sunny14-1.png" alt="" class="wp-image-17088" srcset="https://www.synergex.com/wp-content/uploads/2023/02/Sunny14-1.png 539w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny14-1-300x133.png 300w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny14-1-260x115.png 260w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny14-1-50x22.png 50w, https://www.synergex.com/wp-content/uploads/2023/02/Sunny14-1-150x67.png 150w" sizes="(max-width: 539px) 100vw, 539px" /></figure>



<p>As you can see, YAML gives you a great deal of control for building, testing, and deploying projects. We’ve looked at a simple example of what can be done with YAML, but there are a plenty of complexities that can come into play, and there are other neat tricks that are possible with YAML pipelines. Hopefully it’s apparent that with the right tooling CI/CD isn’t a pipe dream. It is achievable, and it can put you on the path to greater efficiency and faster delivery of your products.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2022/12/19/yaml-your-way-to-rapid-deployment/">YAML Your Way to Rapid Deployment</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2022/12/19/yaml-your-way-to-rapid-deployment/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17073</post-id>	</item>
		<item>
		<title>Select.GroupBy: What’s New and What’s to Come</title>
		<link>https://www.synergex.com/blog/2022/12/19/select-groupby-whats-new-and-whats-to-come/</link>
					<comments>https://www.synergex.com/blog/2022/12/19/select-groupby-whats-new-and-whats-to-come/#respond</comments>
		
		<dc:creator><![CDATA[Tate Chamberlain]]></dc:creator>
		<pubDate>Mon, 19 Dec 2022 16:16:00 +0000</pubDate>
				<category><![CDATA[Tech Article]]></category>
		<category><![CDATA[tech article]]></category>
		<guid isPermaLink="false">https://www.synergex.com/?p=17071</guid>

					<description><![CDATA[<p>Overview The Select class in Synergy DBL allows developers to access data from Synergy DBMS files using syntax and concepts that are closer to SQL than<span class="excerpt-hellip"> […]</span></p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2022/12/19/select-groupby-whats-new-and-whats-to-come/">Select.GroupBy: What’s New and What’s to Come</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>Overview</strong></p>



<p>The Select class in Synergy DBL allows developers to access data from Synergy DBMS files using syntax and concepts that are closer to SQL than to the traditional file-based approach. Since its introduction, the Select class has grown to include more SQL-like features. With Synergy/DE 12, we’ve taken another step in that direction by introducing a new class that can be used with Select: GroupBy. This feature was initially introduced in Synergy/DE 12.1 but has been refined in the recent 12.2.1.1003 feature release.</p>



<p>The GroupBy class implements some of the functionality found in the GROUP BY and DISTINCT keywords in SQL. GroupBy enables you to filter results from a Select query so that similar records are treated as groups instead of individual records. It does this by letting you specify one or more fields, which it will use to sort the result set. Any set of records with the same value in those fields will be treated as a single group, and only one record from the group will be returned as a representative of the whole.</p>



<p><strong>Basic Syntax</strong> The Synergy GroupBy class is derived from the OrderBy class, but the syntax is a bit different. Instead of using the Ascending and Descending methods, you can use a constructor and specify one or more fields to group by, similar to the Sparse class. For example</p>



<pre class="wp-block-code"><code>new GroupBy(firstname)
new GroupBy(lastname, firstname)
</code></pre>



<p>If you want to specify multiple fields, you can combine multiple GroupBy objects with the .AND. or &amp;&amp; operators or just list multiple fields in the same call to Ascending() or Descending(). You can even combine both forms. For example:</p>



<pre class="wp-block-code"><code>grpobj1 = new GroupBy(firstname,lastname)
grpobj2 = new GroupBy(middleinitial)
grpobj3 = grpobj1.and.grpobj2
grpobj4 = new GroupBy(firstname,lastname) &amp;&amp; (new GroupBy(middleinitial))
</code></pre>



<p>In any case, the leftmost field has the highest priority, and the rightmost field has the lowest priority. For grpobj3 and grpobj4 in the example above, records would be sorted first by firstname, then by lastname, and finally by middleinitial.</p>



<p>Ordering is an inherent concept in GroupBy: the returned groups will always be sorted by the specified fields in ascending order.</p>



<p>The constructor generates a GroupBy object, which can either be used inline in a Select constructor or assigned to a variable for later use. For instance:</p>



<pre class="wp-block-code"><code>selobj = new select(sprsobj, fromobj, new GroupBy(firstname,lastname))</code></pre>



<p>or</p>



<pre class="wp-block-code"><code>         grpobj = new GroupBy(firstname,lastname)
selobj = new select(sprsobj, fromobj, grpobj)
</code></pre>



<p>Whenever you use a GroupBy object in a Select query, you must also use a Sparse object. The reasons for this are described in the&nbsp;<strong>Sparse</strong>&nbsp;section below. For now, the examples will use “Sparse(“*”)”, which selects all fields. For example:</p>



<pre class="wp-block-code"><code>selobj = new select(new Sparse("*"), fromobj, new GroupBy(lastname))</code></pre>



<p><strong>Basic Example</strong></p>



<p>To see this in action, consider the following example:</p>



<pre class="wp-block-code"><code>structure employee
    key,           d5
    ,              a1
    firstname,     a15
    ,              a1
    lastname,      a15
    ,              a1
    department,    a15
    ,              a1
    salary,        d7
endstructure

import Synergex.SynergyDE.Select
.main
record
    sprsobj, @Sparse
    fromobj, @From
    selobj,  @Select
    rec1,            employee
record
    count,         i4
    salarysum,     d8
    salaryavg,     d7

.define FILE "DAT:employees.ism"
.proc
    xcall flags(7000000,1)
    open(1, o, "TT:")
    xcall isamc(FILE, ^size(rec1), 1,
&amp;               "START=1, LENGTH=5, NAME=""Key1"", DUPS, ASCEND, ATEND")
        open(2, u:I, FILE)
        store(2, "00001 Andrew          McDonald        Development     0025010")
        store(2, "00002 Bob             Brown           HR              0030020")
        store(2, "00003 Beth            Jones           HR              0035030")
        store(2, "00004 Cathy           Brown           Sales           0040040")
        store(2, "00005 David           SMITH           HR              0045050")
        store(2, "00006 Fred            Smith           QA              0050060")
        store(2, "00007 George          Cartwright      Shipping        0055070")
        store(2, "00008 Henry           Smith           Development     0060080")
        store(2, "00009 Jennifer        Jones           QA              0065090")
        store(2, "00010 James           Mcdonald        Development     0070000")
        store(2, "00011 John            Cartwright      Development     0075010")
        store(2, "00012 Laura           Jones           QA              0080020")
        store(2, "00013 Matthew         Cartwright      Shipping        0085030")
        store(2, "00014 Phillip         Brown           Sales           0090040")
        store(2, "00015 Rose            Jones           Sales           0095050")
        close 2
        open(2, I:I, FILE)
        fromobj = new from(2, rec1)
        writes(1, "")
        writes(1, "OrderBy Department:")
        writes(1, "KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY")
        selobj = new select(fromobj, OrderBy.Ascending(rec1.department))
        foreach rec1 in selobj
        begin
          writes(1,rec1)
        end
        writes(1, "")
        writes(1, "GroupBy Department:")
        writes(1, "KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY")
        sprsobj = new Sparse("*")
        selobj = new select(sprsobj, fromobj, new GroupBy(rec1.department))
        foreach rec1 in selobj
        begin
          writes(1,rec1)
        end
        writes(1, "")
        close 2
        close 1
        stop
.end
</code></pre>



<p>This program creates an ISAM file containing an example table of employees. It runs a Select query with OrderBy to retrieve the full table sorted by department:</p>



<pre class="wp-block-code"><code>OrderBy Department:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
00001 Andrew          McDonald        Development     0025010
00008 Henry           Smith           Development     0060080
00010 James           McDonald        Development     0070000
00011 John            Cartwright      Development     0075010
00002 Bob             Brown           HR              0030020
00003 Beth            Jones           HR              0035030
00005 David           Smith           HR              0045050
00006 Fred            Smith           QA              0050060
00009 Jennifer        Jones           QA              0065090
00012 Laura           Jones           QA              0080020
00004 Cathy           Brown           Sales           0040040
00014 Phillip         Brown           Sales           0090040
00015 Rose            Jones           Sales           0095050
00007 George          Cartwright      Shipping        0055070
00013 Matthew         Cartwright      Shipping        0085030
</code></pre>



<p>It then runs the same query again, using GroupBy instead of OrderBy:</p>



<pre class="wp-block-code"><code>GroupBy Department:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
00001 Andrew          McDonald        Development     0025010
00002 Bob             Brown           HR              0030020
00006 Fred            Smith           QA              0050060
00004 Cathy           Brown           Sales           0040040
00007 George          Cartwright      Shipping        0055070
</code></pre>



<p>In the second query, all of the records with a certain value for department are treated as a single group, and only one record is returned for each group.</p>



<p>Suppose we changed the OrderBy and GroupBy objects to use both rec1.department and rec1.lastname fields instead of just rec1.department:</p>



<pre class="wp-block-code"><code>selobj = new select(fromobj, OrderBy.Ascending(rec1.department, rec1.lastname))
selobj = new select(sprsobj, fromobj, new GroupBy(rec1.department, rec1.lastname))
</code></pre>



<p>The OrderBy query would return the same results as before, but in a slightly different order:</p>



<pre class="wp-block-code"><code>OrderBy Department and Lastname:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
00011 John            Cartwright      Development     0075010
00001 Andrew          McDonald        Development     0025010
00010 James           Mcdonald        Development     0070000
00008 Henry           Smith           Development     0060080
00002 Bob             Brown           HR              0030020
00003 Beth            Jones           HR              0035030
00005 David           SMITH           HR              0045050
00009 Jennifer        Jones           QA              0065090
00012 Laura           Jones           QA              0080020
00006 Fred            Smith           QA              0050060
00004 Cathy           Brown           Sales           0040040
00014 Phillip         Brown           Sales           0090040
00015 Rose            Jones           Sales           0095050
00007 George          Cartwright      Shipping        0055070
00013 Matthew         Cartwright      Shipping        0085030
</code></pre>



<p>But the GroupBy query would return additional records that weren’t present in the original:</p>



<pre class="wp-block-code"><code>GroupBy Department and Lastname:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
00011 John            Cartwright      Development     0075010
00001 Andrew          McDonald        Development     0025010
00010 James           Mcdonald        Development     0070000
00008 Henry           Smith           Development     0060080
00002 Bob             Brown           HR              0030020
00003 Beth            Jones           HR              0035030
00005 David           SMITH           HR              0045050
00009 Jennifer        Jones           QA              0065090
00006 Fred            Smith           QA              0050060
00004 Cathy           Brown           Sales           0040040
00015 Rose            Jones           Sales           0095050
00007 George          Cartwright      Shipping        0055070
</code></pre>



<p>This is because the GroupBy query is now using both fields to determine groups. Records in the new query will only be considered as part of the same group if they have identical values for both department and lastname, instead of just department. If multiple employee records in the same department have the same lastname value, they’ll still be part of the same group, but different last names will result in separate groups.</p>



<p>For the sake of simplicity, the examples here select all records from the data file. But GroupBy will also work with more complicated queries that include a Where expression.</p>



<p><strong>Case Sensitivity</strong></p>



<p>You may have noticed from the previous example that there appear to be two groups with a department value of “Development” and a lastname value of “McDonald”. This is because the default behavior for OrderBy and GroupBy is to use case-sensitive comparisons when sorting records. So “Mc<strong><em>D</em></strong>onald” and “Mc<strong><em>d</em></strong>onald” are distinct values and result in separate groups in GroupBy. This is easy to see if we group by lastname only:</p>



<pre class="wp-block-code"><code>GroupBy Lastname:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
00002 Bob             Brown           HR              0030020
00007 George          Cartwright      Shipping        0055070
00003 Beth            Jones           HR              0035030
00001 Andrew          McDonald        Development     0025010
00010 James           Mcdonald        Development     0070000
00005 David           SMITH           HR              0045050
00006 Fred            Smith           QA              0050060
</code></pre>



<p>If you want to ignore differences in case, you can use the NoCaseGroupBy class instead of the regular GroupBy:</p>



<pre class="wp-block-code"><code>NoCaseGroupBy Lastname:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY\
00002 Bob             Brown           HR              0030020
00007 George          Cartwright      Shipping        0055070
00003 Beth            Jones           HR              0035030
00001 Andrew          McDonald        Development     0025010
00005 David           SMITH           HR              0045050
</code></pre>



<p>We’ve also added the same functionality to OrderBy in the new NoCaseOrderBy class. Note that NoCaseGroupBy and NoCaseOrderBy are only intended to be used with alpha fields and may cause problems if used with any other data type. If you want to use case-insensitive comparisons for some fields and not others, you can create multiple objects and combine them. For example:</p>



<pre class="wp-block-code"><code>new NoCaseGroupBy(alpha_field) &amp;&amp; (new GroupBy(int_field))</code></pre>



<p><strong>Sparse</strong></p>



<p>A Select query using GroupBy will return a record from the data file to represent each group as a whole. Because this is a regular record, we can expect it to contain data in all of its fields, not just the fields used to determine the group. But these fields will probably be meaningless for use in representing the group. We can see this by going back to the “GroupBy(rec1.department)” example:</p>



<pre class="wp-block-code"><code>GroupBy Department:
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
00001 Andrew          McDonald        Development     0025010
00002 Bob             Brown           HR              0030020
00006 Fred            Smith           QA              0050060
00004 Cathy           Brown           Sales           0040040
00007 George          Cartwright      Shipping        0055070
</code></pre>



<p>The only meaningful field in that data is the one used to determine the groups: department. The fact that the employee record returned for the Development department has a name of “Andrew McDonald” doesn’t necessarily tell us anything about the Development department. And the fact that the records for the HR and Sales departments both have a lastname value of “Brown” doesn’t necessarily indicate any similarity between those departments.</p>



<p>It would be helpful to limit the returned data to fields that actually matter. In a SQL query, this could be done by writing a query to only return the fields you care about. In Synergy’s Select class, the fields used by the returned data are determined in advance by the record definition. But you can use the Sparse class to specify the fields that you want returned, leaving all other fields empty. For example:</p>



<pre class="wp-block-code"><code>selobj = new select(new Sparse(rec1.department), fromobj,
&amp;                   new GroupBy (rec1.department))
</code></pre>



<p>which results in</p>



<pre class="wp-block-code"><code>GroupBy Department (Sparse):
KEY   FIRSTNAME       LASTNAME        DEPARTMENT      SALARY
                                      Development
                                      HR
                                      QA
                                      Sales
                                      Shipping
</code></pre>



<p>The primary use case for Sparse is to improve performance when accessing data over&nbsp;<em>xf</em>Server by reducing the amount of data sent over the network. Our documentation warns against using Sparse when you aren’t also using&nbsp;<em>xf</em>Server, as it may not improve performance. But in the case of GroupBy, Sparse can still be useful regardless of any performance impact.</p>



<p>Additionally, because GroupBy now uses a static cursor to sort and return results, Sparse may improve performance even for local files. A static cursor reads all matching records from a data file into memory before processing (e.g., sorting and grouping) and returning them. Using Sparse to reduce the number of returned fields will reduce the amount of data that needs to be kept in memory, which can reduce memory usage and improve performance.</p>



<p>For these reasons, a Sparse object is required for all queries that use a static cursor, such as all GroupBy queries. We strongly recommend using Sparse to limit a GroupBy query to fields that are actually meaningful, but it is still possible to include additional fields, or even to specify “Sparse(“*”)” and include all fields regardless of relevance.</p>



<p><strong>Aggregate Values</strong></p>



<p>While the non-group fields of any given GroupBy record may not be meaningful individually, it may be helpful to use these fields to describe a group as a whole. For instance, it may not be useful to see the salary of the employee record returned for the QA department, because the record might not be representative of the department. But if you could see the average salary for everyone in the department, or the total amount of money the department spends on payroll, that information could be useful.</p>



<p>This brings us to a primary use case of GROUP BY in SQL: aggregate values. In addition to the actual fields from a table, SQL allows you to select aggregate functions to be performed for all fields in a group, such as Sum, Count, Average, Minimum, and Maximum.</p>



<p>At present, the Synergy GroupBy class doesn’t have aggregate functions built in. But it’s possible to calculate aggregate values in code using multiple Select objects. The first Select object can use GroupBy to retrieve distinct values for specific fields. Then a second Select object can use those values to drive a Where expression and iterate over all records in that group. The code can use those records to calculate any aggregate values.</p>



<p><strong>Advanced Example</strong></p>



<p>To see an example of aggregate values, you can add this code after the existing Select objects in the test program:</p>



<pre class="wp-block-code"><code>writes(1, "GroupBy Department with aggregate values:")
            writes(1, "DEPARTMENT         COUNT     AVG(SALARY)  SUM(SALARY)")
            selobj = new select(new Sparse(rec1.department), fromobj,
&amp;                               new GroupBy(rec1.department))
            foreach rec1 in selobj
            begin
                data selobj2, @Select
                data rec2, employee
                open(3, I:I, FILE)
                count = 0
                salarysum = 0
                salaryavg = 0
                selobj2 = new Select(new From(3,rec2),
&amp;                                    (Where)(rec2.department == rec1.department))
                foreach rec2 in selobj2
                  begin
                      count += 1
                      salarysum += rec2.salary
                  end
                salaryavg = salarysum/count
                writes(1,rec1.department + "    " + %string(count,"XX") +
&amp;                      "    " + %string(salaryavg,"$$$,$$$,$$$") +
&amp;                      "    " + %string(salarysum,"$$,$$$,$$$"))
                close 3
            end
</code></pre>



<p>After running this program, you should get output like this:</p>



<pre class="wp-block-code"><code>GroupBy Department with aggregate values:
DEPARTMENT         COUNT     AVG(SALARY)  SUM(SALARY)
Development        04        $57,525      $230,100
HR                 03        $36,700      $110,100
QA                 03        $65,056      $195,170
Sales              03        $75,043      $225,130
Shipping           02        $70,050      $140,100
</code></pre>



<p>This code uses GroupBy to return individual records for each department. Within the outer FOREACH loop, another Select object retrieves all records that match each group and keeps a running total of the number of records and the salary for all records in the department. After it’s done reading the records, the code calculates the average salary for the department and displays the data to the screen.</p>



<p>A downside to this method is that there’s no built-in way to sort groups based on an aggregate value. The order of groups is based on the field used in the GroupBy, and any ordering based on aggregate values would need to be done after the initial Select is finished and all aggregate values are calculated.</p>



<p><strong>Limitations</strong></p>



<p>At the time of this writing, the current syntax for GroupBy (introduced in 12.2.1.1003) can only be used when targeting the latest runtime. If you’re building a Synergy program from the command line, this means you must include an option like “-qrntcompat=120301” in the compiler and linker commands. If you’re building from Visual Studio, you can select a Target Synergy runtime of “Latest” in the Build properties for the project. (The original syntax introduced in 12.1 that uses Ascending() and Descending() methods, similar to the OrderBy class, can be used when targeting the default 120101 runtime level, but that syntax is no longer recommended.)</p>



<p>GroupBy requires compiler and runtime features that aren’t present in earlier versions of Synergy. You won’t be able to compile code that uses GroupBy if you target an earlier Synergy version. (In other words, if you use the -qrntcompat compiler and linker option, you can’t specify a version number prior to 12010100.) Likewise, if you’re accessing data over&nbsp;<em>xf</em>Server, the server must be running at least version 12 for GroupBy to work. By default, an&nbsp;<em>xf</em>Server client of version 12.2.1.1003 or later can only connect to a server of version 12.2.1.1003 or later, although you can use the SRV_COMPAT environment variable to override this and connect to a server with an earlier version.</p>



<p>At present, GroupBy is not supported with a JoinSelect. Queries using GroupBy must operate on a single file only. Likewise, GroupBy and OrderBy are not supported on the same query, although results returned by GroupBy will be sorted in ascending order.</p>



<p>GroupBy uses a static cursor and so operates on a snapshot of the data file at the time when the enumerator is created. As a result, it’s possible for the underlying data to change between the time when the Select statement starts working and the time when it retrieves any given record. This shouldn’t change the order of any groups, but it could result in new groups being skipped if records belonging to that group are only added after the Select has started working.</p>



<p>Because each result returned by a GroupBy query represents a group of records instead of a single record in a file, several Select features that require individual records won’t work. For instance, the RestrictedAlphaEnumerator methods CurrentRFA and DeleteCurrent are incompatible with GroupBy. A GroupBy result will have no change tracking information, so the GetCTInfo property is also incompatible. Record locking is incompatible with a GroupBy query, and a GroupBy query won’t execute if locks are enabled in the From object, so the IsLocked property is incompatible as well. The SparseUpdate method is also incompatible, because it can’t be used on a query with a Sparse object, and Sparse objects are required when using GroupBy.</p>



<p>In some circumstances (e.g., if it’s sorting by a single key that’s already in the correct order in the ISAM file), OrderBy can optimize a query by bypassing the process of sorting records and returning them in the correct order directly from the file. GroupBy doesn’t support this but will always sort the result set regardless of what fields are specified. This may result in slower performance than would otherwise be possible for some queries.</p>



<p>As mentioned above, aggregate functions are not currently supported with GroupBy.</p>



<p><strong>Future Plans</strong></p>



<p>While future plans have not been finalized, we’re considering addressing many of the above limitations in future releases of Synergy/DE. One of the biggest improvements we’d like to make in the near future is to support GroupBy with JoinSelect, similar to the support we recently added to use OrderBy with JoinSelect. We’d also like to support OrderBy and GroupBy on the same queries.</p>



<p>In the longer term, we’d like to support aggregate functions with GroupBy (Sum, Count, Average, Minimum, and Maximum), bringing feature parity closer to SQL. Ideally, this feature would allow arbitrary mapping of grouped and aggregated fields from a source record into a destination record, with arbitrary sorting of the results. This mapping could also be useful in other contexts besides GroupBy.</p>



<p>Another potential change is to optimize GroupBy, perhaps by returning records directly from memory after sorting them, instead of reading records from the ISAM file when retrieving them. We might also have GroupBy imply Sparse, so results aren’t cluttered by meaningless records and performance over&nbsp;<em>xf</em>Server is improved, without requiring an explicit definition of a Sparse object.</p>



<p>These changes will likely require new versions of the compiler, runtime, and&nbsp;<em>xf</em>Server, so backwards compatibility is one limitation we wouldn’t be addressing.</p>



<p><strong>Conclusion</strong></p>



<p>I hope this article has given you a good introduction to the GroupBy class. You should have some idea of how the class can be used, both theoretically and with practical code examples. You should also have a basic understand of the differences between the Synergy GroupBy class and SQL, as well as the current limitations of the class, but also some insight into how the class may develop in the future.</p>
<p>The post <a rel="nofollow" href="https://www.synergex.com/blog/2022/12/19/select-groupby-whats-new-and-whats-to-come/">Select.GroupBy: What’s New and What’s to Come</a> appeared first on <a rel="nofollow" href="https://www.synergex.com">Synergex</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.synergex.com/blog/2022/12/19/select-groupby-whats-new-and-whats-to-come/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17071</post-id>	</item>
	</channel>
</rss>
