اشتراکها
اشتراکها
مشکلات SQLite
Gridify همچنان در حال توسعه است ولی کاربرد این کتابخانه تبدیل string به Linq هست و صرفا مختص کار با EF و دیتابیس نیست. به همین جهت فکر نمیکنم چنین فیچری رو بهش اضافه کنم. البته شاید در قالب یک Extension library برای EF بشه بهش فکر کرد, ولی در حال حاضر جزء roadmap کتابخانه نیست.
سلام
با تشکر از زحمات شما
به نظر من استفاده از #F در کنار #C به عنوان Library برای حل مسائل خاص خیلی میتونه مفید باشه
اگه ممکنه در مورد صورت مسئله و راه حلهای ارائه شده با #F بیشتر بنویسید تا بیشتر مورد استفاده قرار بگیره ،و خیلی کاربردیتر موضوع رو ببینیم
ممنون
با تشکر از زحمات شما
به نظر من استفاده از #F در کنار #C به عنوان Library برای حل مسائل خاص خیلی میتونه مفید باشه
اگه ممکنه در مورد صورت مسئله و راه حلهای ارائه شده با #F بیشتر بنویسید تا بیشتر مورد استفاده قرار بگیره ،و خیلی کاربردیتر موضوع رو ببینیم
ممنون
نظرات مطالب
LINQ to Sharepoint Class
منبع در مورد Join زیاد هست :
و...
نظرات مطالب
سیلورلایت 5 و تاریخ شمسی
سلام.
جناب نصیری، من توی ساپورت و کانکت ماکروسافت، جایی برای ارسال درخواست درباره اضافه شدن تقویم فارسی به datepicker مترو استایل، پیدا نکردم، درخواست راهنمایی از طرف شما را دارم: http://msdn.microsoft.com/en-US/library/windows/apps/hh465480
در قسمت اول این سری، با مدل برنامه نویسی Event based asynchronous pattern ارائه شده از دات نت 2 و همچنین APM یا Asynchronous programming model موجود از نگارش یک دات نت، آشنا شدیم (به آن الگوی IAsyncResult هم گفته میشود). نکتهی مهم این الگوها، استفادهی گسترده از آنها در کدهای کلاسهای مختلف دات نت فریم ورک است و برای بسیاری از آنها هنوز async API سازگار با نگارش مبتنی بر Taskهای سیشارپ 5 ارائه نشدهاست. هرچند دات نت 4.5 سعی کردهاست این خلاء را پوشش دهد، برای مثال متد الحاقی DownloadStringTaskAsync را به کلاس WebClient اضافه کردهاست و امثال آن، اما هنوز بسیاری از کلاسهای دیگر دات نتی هستند که معادل Task based API ایی برای آنها طراحی نشدهاست. در ادامه قصد داریم بررسی کنیم چگونه میتوان این الگوهای مختلف قدیمی برنامه نویسی غیرهمزمان را با استفاده از روشهای جدیدتر ارائه شده بکار برد.
نگاشت APM به یک Task
در قسمت اول، نمونه مثالی را از APM، که در آن کار با BeginGetResponse آغاز شده و سپس در callback نهایی توسط EndGetResponse، نتیجهی عملیات به دست میآید، مشاهده کردید. در ادامه میخواهیم یک محصور کنندهی جدید را برای این نوع API قدیمی تهیه کنیم، تا آنرا به صورت یک Task ارائه دهد.
همانطور که در این مثال مشاهده میکنید، یک چنین سناریوهایی در TPL یا کتابخانهی Task parallel library پیش بینی شدهاند. در اینجا یک محصور کننده برای متدهای BeginRead و EndRead کلاس Stream دات نت ارائه شدهاست. به عمد نیز به صورت یک متد الحاقی تهیه شدهاست تا در حین استفاده از آن اینطور به نظر برسد که واقعا کلاس Stream دارای یک چنین متد Async ایی است. مابقی کار توسط متد Task.Factory.FromAsync انجام میشود. متد FromAsync دارای امضاهای متعددی است تا اکثر حالات APM را پوشش دهد.
در مثال فوق BeginRead و EndRead استفاده شده از نوع delegate هستند. چون خروجی EndRead از نوع int است، خروجی متد نیز از نوع Task of int تعیین شدهاست. همچنین سه پارامتر ابتدایی BeginRead ، دقیقا data، offset و count هستند. دو پارامتر آخر آن callback و state نام دارند. پارامتر callback توسط متد FromAsync فراهم میشود و state نیز در اینجا null درنظر گرفته شدهاست.
یک مثال استفاده از آنرا در ادامه مشاهده میکنید:
File.OpenRead، خروجی از نوع استریم دارد. سپس متد الحاقی ReadAsync بر روی آن فراخوانی شدهاست و نهایتا تعداد بایت خوانده شده نمایش داده میشود.
البته همانطور که پیشتر نیز عنوان شد، استفاده از خاصیت Result، اجرای کد را بجای غیرهمزمان بودن، به حالت همزمان تبدیل میکند.
در اینجا چون خروجی متد ReadAsync یک Task است، میتوان از متد ContinueWith نیز بر روی آن جهت دریافت نتیجه استفاده کرد:
یک نکته
پروژهی سورس بازی به نام Async Generator در GitHub، سعی کردهاست برای ساده سازی نوشتن محصور کنندههای مبتنی بر Task روش APM، یک Code generator تولید کند. فایلهای آنرا از آدرس ذیل میتوانید دریافت کنید:
نگاشت EAP به یک Task
نمونهای از Event based asynchronous pattern یا EAP را در قسمت اول، زمانیکه روال رخدادگردان webClient.DownloadStringCompleted را بررسی کردیم، مشاهده نمودید. کار کردن با آن نسبت به APM بسیار سادهتر است و نتیجهی نهایی عملیات غیرهمزمان را در یک روال رخدادگران، در اختیار استفاده کننده قرار میدهد. همچنین در روش EAP، اطلاعات در همان Synchronization Context ایی که عملیات شروع شدهاست، بازگشت داده میشود. به این ترتیب اگر آغاز کار در ترد UI باشد، نتیجه نیز در همان ترد دریافت خواهد شد. به این ترتیب دیگر نگران دسترسی به مقدار آن در کارهای UI نخواهیم بود؛ اما در APM چنین ضمانتی وجود ندارد.
متاسفانه TPL همانند روش FromAsync معرفی شده در ابتدای بحث، راه حل توکاری را برای محصور سازی متدهای روش EAP ارائه ندادهاست. اما با استفاده از امکانات TaskCompletionSource آن میتوان چنین کاری را انجام داد. در ادامه سعی خواهیم کرد همان متد الحاقی توکار DownloadStringTaskAsync ارائه شده در دات نت 4.5 را از صفر بازنویسی کنیم.
روش انجام کار را در اینجا ملاحظه میکنید. ابتدا باید تعاریف delaget مرتبط با رخدادگردان Completed اضافه شوند. یکبار += را ملاحظه میکنید و بار دوم -= را. مورد دوم جهت آزاد سازی منابع و جلوگیری از نشتی حافظهی روال رخدادگردان هنوز متصل، ضروری است.
سپس از TaskCompletionSource برای تبدیل این عملیات به یک Task کمک میگیریم. اگر args.Cancelled مساوی true باشد، یعنی عملیات دریافت فایل لغو شدهاست. بنابراین متد SetCanceled منبع Task ایجاد شده را فراخوانی خواهیم کرد. این مورد استثنایی را در کدهای فراخوان سبب میشود. به همین دلیل بررسی خطا با یک if else پس از آن انجام شدهاست. برای بازگشت خطای دریافت شده از متد SetException و برای بازگشت نتیجهی واقعی دریافتی، از متد SetResult میتوان استفاده کرد.
به این ترتیب متد الحاقی غیرهمزمان جدیدی را به نام DownloadTextTaskAsync برای محصور سازی متد EAP ایی به نام DownloadStringAsync و همچنین رخدادگران آن تهیه کردیم.
نگاشت APM به یک Task
در قسمت اول، نمونه مثالی را از APM، که در آن کار با BeginGetResponse آغاز شده و سپس در callback نهایی توسط EndGetResponse، نتیجهی عملیات به دست میآید، مشاهده کردید. در ادامه میخواهیم یک محصور کنندهی جدید را برای این نوع API قدیمی تهیه کنیم، تا آنرا به صورت یک Task ارائه دهد.
public static class ApmWrapper { public static Task<int> ReadAsync(this Stream stream, byte[] data, int offset, int count) { return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, data, offset, count, null); } }
در مثال فوق BeginRead و EndRead استفاده شده از نوع delegate هستند. چون خروجی EndRead از نوع int است، خروجی متد نیز از نوع Task of int تعیین شدهاست. همچنین سه پارامتر ابتدایی BeginRead ، دقیقا data، offset و count هستند. دو پارامتر آخر آن callback و state نام دارند. پارامتر callback توسط متد FromAsync فراهم میشود و state نیز در اینجا null درنظر گرفته شدهاست.
یک مثال استفاده از آنرا در ادامه مشاهده میکنید:
using System; using System.IO; using System.Threading.Tasks; namespace Async06 { public static class ApmWrapper { public static Task<int> ReadAsync(this Stream stream, byte[] data, int offset, int count) { return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, data, offset, count, null); } } class Program { static void Main(string[] args) { using (var stream = File.OpenRead(@"..\..\program.cs")) { var data = new byte[10000]; var task = stream.ReadAsync(data, 0, data.Length); Console.WriteLine("Read bytes: {0}", task.Result); } } } }
البته همانطور که پیشتر نیز عنوان شد، استفاده از خاصیت Result، اجرای کد را بجای غیرهمزمان بودن، به حالت همزمان تبدیل میکند.
در اینجا چون خروجی متد ReadAsync یک Task است، میتوان از متد ContinueWith نیز بر روی آن جهت دریافت نتیجه استفاده کرد:
using (var stream = File.OpenRead(@"..\..\program.cs")) { var data = new byte[10000]; var task = stream.ReadAsync(data, 0, data.Length); task.ContinueWith(t => Console.WriteLine("Read bytes: {0}", t.Result)).Wait(); }
یک نکته
پروژهی سورس بازی به نام Async Generator در GitHub، سعی کردهاست برای ساده سازی نوشتن محصور کنندههای مبتنی بر Task روش APM، یک Code generator تولید کند. فایلهای آنرا از آدرس ذیل میتوانید دریافت کنید:
نگاشت EAP به یک Task
نمونهای از Event based asynchronous pattern یا EAP را در قسمت اول، زمانیکه روال رخدادگردان webClient.DownloadStringCompleted را بررسی کردیم، مشاهده نمودید. کار کردن با آن نسبت به APM بسیار سادهتر است و نتیجهی نهایی عملیات غیرهمزمان را در یک روال رخدادگران، در اختیار استفاده کننده قرار میدهد. همچنین در روش EAP، اطلاعات در همان Synchronization Context ایی که عملیات شروع شدهاست، بازگشت داده میشود. به این ترتیب اگر آغاز کار در ترد UI باشد، نتیجه نیز در همان ترد دریافت خواهد شد. به این ترتیب دیگر نگران دسترسی به مقدار آن در کارهای UI نخواهیم بود؛ اما در APM چنین ضمانتی وجود ندارد.
متاسفانه TPL همانند روش FromAsync معرفی شده در ابتدای بحث، راه حل توکاری را برای محصور سازی متدهای روش EAP ارائه ندادهاست. اما با استفاده از امکانات TaskCompletionSource آن میتوان چنین کاری را انجام داد. در ادامه سعی خواهیم کرد همان متد الحاقی توکار DownloadStringTaskAsync ارائه شده در دات نت 4.5 را از صفر بازنویسی کنیم.
public static class WebClientExtensions { public static Task<string> DownloadTextTaskAsync(this WebClient web, string url) { var tcs = new TaskCompletionSource<string>(); DownloadStringCompletedEventHandler handler = null; handler = (sender, args) => { web.DownloadStringCompleted -= handler; if (args.Cancelled) { tcs.SetCanceled(); } else if(args.Error!=null) { tcs.SetException(args.Error); } else { tcs.SetResult(args.Result); } }; web.DownloadStringCompleted += handler; web.DownloadStringAsync(new Uri(url)); return tcs.Task; } }
سپس از TaskCompletionSource برای تبدیل این عملیات به یک Task کمک میگیریم. اگر args.Cancelled مساوی true باشد، یعنی عملیات دریافت فایل لغو شدهاست. بنابراین متد SetCanceled منبع Task ایجاد شده را فراخوانی خواهیم کرد. این مورد استثنایی را در کدهای فراخوان سبب میشود. به همین دلیل بررسی خطا با یک if else پس از آن انجام شدهاست. برای بازگشت خطای دریافت شده از متد SetException و برای بازگشت نتیجهی واقعی دریافتی، از متد SetResult میتوان استفاده کرد.
به این ترتیب متد الحاقی غیرهمزمان جدیدی را به نام DownloadTextTaskAsync برای محصور سازی متد EAP ایی به نام DownloadStringAsync و همچنین رخدادگران آن تهیه کردیم.
تا اینجا روش آزمایش تولید کنندههای کد، صرفا بر اساس کامپایل برنامه و مشاهدهی خروجی نهایی آن بود و یا حتی با ترفندهایی امکان دیباگ آنها نیز وجود دارد که البته هنوز در تمام IDEها پشتیبانی نمیشود. در این قسمت میخواهیم این وضعیت را بهبود بخشیده و برای تولید کنندههای کد، آزمون واحد بنویسیم که یکی از مزایای آن، فراهم بودن امکان دیباگ یک چنین پروژههایی در تمام IDEهای موجود است و برای انجام اینکار، نیاز به هیچ ترفند خاصی وجود ندارد و پروسهی کاری آن یکدست و هماهنگ با سایر آزمونهای واحد است.
آماده سازی مقدمات پروژهی آزمون واحد
در ادامهی مثال این سری، پروژهی جدید NotifyPropertyChangedGenerator.Tests را از نوع class library با تنظیمات فایل csproj. زیر ایجاد میکنیم:
در اینجا وابستگیهای مورد نیاز برای دسترسی به امکانات Roslyn و همچنین برای نمونه MSTest را مشاهده میکنید. به علاوه مسیر پروژهی Source Generator مورد استفاده به نحو متداولی تعریف شدهاست.
ایجاد یک کلاس کمکی برای اجرای Source Generators در پروژههای آزمون واحد
در اینجا میخواهیم همان کاری را که کامپایلر سیشارپ در پشت صحنه انجام میدهد، شبیه سازی کنیم تا بتوانیم یک تولید کنندهی کد را به مراحل کامپایل کد، معرفی و سپس آنرا اجرا کنیم:
این متد، یک قطعه کد ابتدایی را دریافت کرده و سپس آنرا به همراه Source Generatorهای مدنظر، به کامپایلر سیشارپ معرفی میکند، تا کامپایلر تمام این موارد را در کنار هم پردازش کرده و اسمبلی درون حافظهای را به نام compilation تولید کند. خروجیهای این متد، اطلاعات غنی هستند از نحوهی کامپایل دادههای ارسالی به کامپایلر که در ادامه میتوان از آنها جهت نوشتن آزمونهای واحد متکی به خودی استفاده کرد.
نوشتن اولین آزمون واحد مخصوص یک تولید کنندهی کد
پس از تهیهی متدی که میتواند یک قطعه کد و تعدادی Source Generator را به کامپایلر سیشارپ، جهت پردازش معرفی کند، یک نمونه نحوهی استفادهی از آن جهت نوشتن آزمونهای واحد کاملا مستقل و متکی به خود، به صورت زیر است:
- در این مثال ابتدا یک قطعه کد سیشارپ را که قرار است کدهای آن توسط تولید کنندهی کد توسعه داده شده تکمیل شوند، تعریف کردهایم.
- سپس این قطعه کد و نمونهای از تولید کنندهی کد را به کامپایلر ارسال و اجرا کردهایم.
- اکنون بر اساس خروجی کامپایلر برای مثال میتوان به فایل تولید شده و SyntaxTrees آن دسترسی پیدا کرد و یا با کمک متد GetText، به کل محتوای این فایل تولید شده دسترسی یافت و برای مثال آنرا با مقداری که انتظار داریم مقایسه کرد تا به این ترتیب بتوان از صحت عملکرد تولید کنندهی کد، اطمینان حاصل نمود.
- همانطور که عنوان شد، اکنون قرار دادن break-point در قسمتهای مختلف آزمون واحد تهیه شده بسیار سادهاست و به این ترتیب میتوان یک چنین پروژههایی را در تمام IDEها دیباگ کرد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: SourceGeneratorTests-part5.zip
آماده سازی مقدمات پروژهی آزمون واحد
در ادامهی مثال این سری، پروژهی جدید NotifyPropertyChangedGenerator.Tests را از نوع class library با تنظیمات فایل csproj. زیر ایجاد میکنیم:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.2.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> <PackageReference Include="MSTest.TestFramework" Version="2.2.10" /> <PackageReference Include="MSTest.TestAdapter" Version="2.2.10" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NotifyPropertyChangedGenerator\NotifyPropertyChangedGenerator.csproj" /> </ItemGroup> </Project>
ایجاد یک کلاس کمکی برای اجرای Source Generators در پروژههای آزمون واحد
در اینجا میخواهیم همان کاری را که کامپایلر سیشارپ در پشت صحنه انجام میدهد، شبیه سازی کنیم تا بتوانیم یک تولید کنندهی کد را به مراحل کامپایل کد، معرفی و سپس آنرا اجرا کنیم:
internal static class SourceGeneratorTestsExtensions { public static (GeneratorDriver Driver, Compilation OutputCompilation, ImmutableArray<Diagnostic> Diagnostics) RunGenerators(this string source, params ISourceGenerator[] generators) { var references = AppDomain.CurrentDomain.GetAssemblies() .Where(assembly => !assembly.IsDynamic) .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) .Cast<MetadataReference>(); var inputCompilation = CSharpCompilation.Create("compilation", new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Latest)) }, references, new CSharpCompilationOptions(OutputKind.ConsoleApplication)); GeneratorDriver driver = CSharpGeneratorDriver.Create(generators); driver = driver.RunGeneratorsAndUpdateCompilation( inputCompilation, out var outputCompilation, out var diagnostics); return (driver, outputCompilation, diagnostics); } }
نوشتن اولین آزمون واحد مخصوص یک تولید کنندهی کد
پس از تهیهی متدی که میتواند یک قطعه کد و تعدادی Source Generator را به کامپایلر سیشارپ، جهت پردازش معرفی کند، یک نمونه نحوهی استفادهی از آن جهت نوشتن آزمونهای واحد کاملا مستقل و متکی به خود، به صورت زیر است:
using Microsoft.VisualStudio.TestTools.UnitTesting; using PropertyChangedGenerator = NotifyPropertyChangedGenerator.NotifyPropertyChangedGenerator; namespace NotifyPropertyChangedGenerator.Tests; [TestClass] public class GeneratorTest { [TestMethod] public void SimpleGeneratorTest() { var userSource = @" using System; using System.ComponentModel; namespace NotifyPropertyChangedDemo { public class Test : INotifyPropertyChanged { private int regularField; private int IndexBackingField; } } "; var (driver, outputCompilation, diagnostics) = userSource.RunGenerators(new PropertyChangedGenerator()); var newFile = outputCompilation.SyntaxTrees .Single(x => Path.GetFileName(x.FilePath).EndsWith(".Test.cs")); Assert.IsNotNull(newFile); Assert.IsTrue(newFile.FilePath.EndsWith("Test.Notify.Test.cs")); var generatedSource = newFile.GetText().ToString(); Assert.IsTrue(generatedSource.Contains("namespace NotifyPropertyChangedDemo")); // We can now assert things about the resulting compilation: Assert.IsTrue(diagnostics.IsEmpty); // there were no diagnostics created by the generators // we have two syntax trees, the original 'user' provided one, and the one added by the generator Assert.IsTrue(outputCompilation.SyntaxTrees.Count() == 2); // verify the compilation with the added source has no diagnostics Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); } }
- سپس این قطعه کد و نمونهای از تولید کنندهی کد را به کامپایلر ارسال و اجرا کردهایم.
- اکنون بر اساس خروجی کامپایلر برای مثال میتوان به فایل تولید شده و SyntaxTrees آن دسترسی پیدا کرد و یا با کمک متد GetText، به کل محتوای این فایل تولید شده دسترسی یافت و برای مثال آنرا با مقداری که انتظار داریم مقایسه کرد تا به این ترتیب بتوان از صحت عملکرد تولید کنندهی کد، اطمینان حاصل نمود.
- همانطور که عنوان شد، اکنون قرار دادن break-point در قسمتهای مختلف آزمون واحد تهیه شده بسیار سادهاست و به این ترتیب میتوان یک چنین پروژههایی را در تمام IDEها دیباگ کرد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: SourceGeneratorTests-part5.zip
نقل قولهای زیادی، در مورد کیفیت کد وجود دارند. دستور العملهای فراوانی نیز در این راستا وجود دارند. یکی از ابزارهایی که برای نوشتن کدهایی با کیفیت مطلوب وجود دارد، مجموعه الگوهای بد کد نویسی است که به Code smell یا بوی بد کد مشهور هستند.
بوی بد کد، نشانههایی در کد هستند که حکایت از مشکلات عمیقتری دارند. بوی بد کد مساوی با باگ نیست. ولی خطر افزایش باگها و یا مشکلاتی را در آینده، به دنبال خواهند داشت. بوی بد کد معمولا حاصل رعایت نکردن یک سری اصول اولیه برنامه نویسی و یا طراحی شیء گرا هستند.
برای بهبود کیفیت نرم افزار در دراز مدت نیاز است موارد بوی بد کد به دقت بررسی و رفع شوند. رفع شدن آنها ریسک انباشته شدن بوی بد کد را در پروژه کم خواهد کرد. یکی از فواید جلوگیری از انباشته شدن چنین الگوهای بدی در پروژه، بهبود فرآیند نگهداشت آن میباشد که موضوعی بسیار مهم برای چابکی یک تیم نرم افزاری است.
هنگام مشاهدهی بوی بد، در بخشی از کدها، معمولا اولین اقدام، رفع آن است (Refactoring). در فرآیند رفع آن ممکن است الگوهای بد دیگری در کد یافت شوند که با آنها نیز به همین صورت برخورد خواهد شد.
انوع بوهای بد کد به دستههای زیر طبقه بندی میشوند.
کدهای متورم (Bloaters)
این دسته در واقع تکه کدهایی (متد، کلاس و ...) هستند که به دلیل بزرگی بیش از اندازه عملا امکان کار با آنها وجود ندارد. این بخشهای بزرگ کد معمولا با توسعه تدریجی محصول ایجاد و روی هم انباشته میشوند. بوهای بد این دسته بندی به صورت زیر هستند:
1 - متدهای بلند (Long method): در این الگوی بد، متدها تعداد خطهای زیادی از کد را شامل میشوند. به طور معمول متدهایی با تعداد خطوط بیشتر از 10 خط، متدهای بلند محسوب میشوند. نکته قابل توجه این است که هیچ کس متدی را با تعداد خطوط زیاد طراحی نمیکند! معمولا به مرور زمان تعداد خطهای یک متد افزایش مییابند.
2 - کلاسهای بزرگ (Large class): کلاسی که تعداد فیلدها، متدها و خطوط کد زیادی دارد.
3 - وسواس استفاده از متغیرهای دادهای اولیه (Primitive obsession): این بوی بد معمولا به سه شکل بروز میکند.
- استفاده از متغیرهای اولیه بجای ساختارهای کوچک برای کارهای اولیه مانند Currency, DateTime, PhoneNumber
- استفاده از constantها برای کد کردن اطلاعات مانند USER_ADMIN_ROLE = 1
- استفاده از constantهای رشتهای به عنوان نام فیلدها در آرایههای داده
4 - تعداد پارامترهای زیاد متد (Long parameter list): تعداد پارامترهای بیشتر از سه یا چهار عدد در یک متد.
5 - توده داده (Data clumps): در بعضی موارد ممکن است از متغیرها به صورت دستهای در مکانهای مختلف کد استفاده شود. مانند استفاده از دستهای از متغیرها برای نگه داشتن اطلاعات مربوط به اتصال پایگاه داده. این دستهها باید به کلاسهای حمل کننده داده خود تغییر کنند.
بد استفاده کنندگان از شیء گرایی (Object orientation abusers)
تکه کدهای این بخش در واقع بد استفاده کنندگاه یا ناقص استفاده کنندگان از اصول شیء گرایی هستند. در این دسته بندی موارد زیر وجود دارند:
1 - گذارههای switch: وجود یک گذاره switch پیچیده یا دنبالهای از گذارههای if
2 - درخواست رد شده (Refused request): در این حالت یک کلاس مجموعه محدودی از اعضای کلاس پدر خود را پیاده سازی میکند و باقی اعضای کلاس پدر یا بدون استفاده میمانند یا با استفاده از پرتاب کردن استثناء (Exception throwing) از کار انداخته میشوند.
3 - فیلد موقتی (Temporary field): در این حالت متغیرها مقدار خود را در شرایط خاصی میگیرند و در بقیه شرایط خالی هستند.
4 - کلاس هایی دقیقا مشابه در کارایی ولی متفاوت در مشخصات (Alternative Classes with Different Interfaces): دو کلاس دقیقا یک کار را انجام میدهند ولی نام اعضای آنها (متد و ...) متفاوت است.
جلوگیری کنندگان از تغییر(Change preventers)
این نشانهها حاکی از این دارند زمانیکه تغییری در یک بخش کد نیاز باشد، در راستای آن حتما باید دیگر بخشهای کد نیز به مقدار زیادی تغییر کنند. در این حالات اعمال تغییرات و نگهداری کد به شدت سخت خواهد شد.
مواردی که در این دسته بندی قرار دارند به صورت زیر میباشند:
1 - تغییر واگرا (Divergent change): این حالت زمانی اتفاق میافتد که برای اعمال یک تغییر به کلاس نیاز است متدهای زیادی را تغییر دهید. به طور مثال به ازای هر نوع محصولی که به محصولات شما اضافه میشود باید متدهای ذخیره، بازیابی، جستجو را تغییر دهید.
2 - Shotgun Surgery: این حالت شباهت زیادی به تغییر واگرا دارد. تنها تفاوت آن این است که در این حالت شما به ازای هر تغییر نیاز است کلاسهای زیادی را تغییر دهید. تغییر واگرا در بدنه یک کلاس اتفاق میافتد.
3 - سلسله مراتب موازی ارث بری (Parallel inheritance hierarchy): این مورد یکی کمتر درک شدهترین موارد است. در این حالت زمانی که یک زیر کلاس برای یک کلاس ایجاد میکنید به ازای آن ناخودآگاه مجبور میشوید یک زیر کلاس برای کلاس دیگری ایجاد کنید.
کدهای غیر ضروری (Dispensables)
این دسته از کدها معمولا کدهایی هستند بی دلیل و بی استفاده. کدهایی که نبودنشان بهتر از بودنشان است! حذف کردن این کدها به خوانایی و قابلیت نگهداری کد خواهد افزود. بوهای بدی که در این دسته بندی قرار دارند به صورت زیر میباشند:
1 - کامنت: یک متد، با مقادیر فراوانی از کامنتهای توضیحی پر شده است.
2 - کد تکراری: در این بوی بد، دو قطعه کد دقیقا مانند یکدیگر هستند.
3 - کلاس داده (ِData class): کلاسهایی که تنها فیلدهای اطلاعاتی در آنها وجود دارند و متدهای خامی که جهت دریافت یا ذخیره اطلاعات در آنها استفاده میشوند. این کلاسهای معمولا هیچ روال منطقی ای در خود ندارند. یکی از قدرتهای شیء گرایی افزودن رفتار به کلاسها در کنار اقلام اطلاعاتی موجود در آن است.
4 - کلاس تنبل (Lazy class): اگر کلاس کار چندانی که درخور نگهداری و توسعه باشد، انجام نمیدهد بهتر است از بین برود.
5 - کد مرده (Dead code): متغیر، پارامتر، متد یا کلاسی که دیگر هیچ استفادهای از آن متصور نیست و هیچ استفادهای در حال حاضر از آن وجود ندارد.
6 - کلی نگری بیش از اندازه (Speculative Generality): این الگو نیز کدهایی را شامل میشود که بلااستفاده هستند. ولی دلیل بلااستفاده بودن آن کلی نگری و دور اندیشی بدون دلیل است. معمولا کدهای تولیدی برای شرایط فعلی و پیشبینی آینده تولید میشوند. اگر این پیشبینی آینده به درستی و بر مبنای واقعیات انجام نشود، معمولا نتیجه کار، طراحی و پیاده سازی ای بی فایده و بلااستفاده خواهد بود.
کدهایی بیش از اندازه وابسته به هم (Couplers)
کدهایی که در این دسته قرار میگیرند معمولا یا خود درگیر یک وابستگی شدید هستند یا به ایجاد وابستگی بین کلاسها کمک میکنند. بویهای بدی که در این دسته بندی قرار میگیرند به صورت زیر هستند:
1- متد حسود (Feature envy): متدی که از اعضای یک شیء دیگر بیشتر از اعضای کلاس خود استفاده میکند! این اتفاق معمولا زمانی میافتد که فیلدهایی به یک "کلاس داده" منتقل میشوند. وقتی این اتفاق میافتد یکی از راه حلها، انتقال روالهای استفاده کننده از فیلدها به "کلاس داده" مربوطه است.
2 - کلاسهای بیش از اندازه صمیمی (Inappropriate Intimacy): کلاسها از اعضای internal یکدیگر بیش از اندازه استفاده میکنند. کلاسهای خوب کلاسهایی هستند که کمترین اطلاعی را از وضعیت داخلی یکدیگر دارند.
3 - کتابخانههای ناقص (Incomplete Library Class): زمانیکه کتابخانهای آماده میشود، بالاخره روزی میرسد که این کتابخانه نیازهای پروژه را رفع نمیکند و نیاز به توسعه خواهد داشت. ولی از آنجایی که کتابخانهها به صورت فقط خواندنی در اختیار پروژهها قرار میگیرند، در صورتیکه توسعه دهنده اصلی آن از توسعه کتابخانه سر باز بزند، مشکلاتی بوجود خواهد آمد.
4 - زنجیره فراخوانیها (Message chain): زمانیکه یک متد در بدنه خود پیامی به شیء دیگری میفرستد که آن شیء نیز به خودی خود پیامی به شیء دیگری میفرستد (و الی آخر) یک زنجیره فراخوانی بوجود آمده است. در این روش بیرونیترین استفاده کننده از متد در واقع وابسته به یک زنجیرهای از فراخوانیها است که تغییر در هر قدمی از آن باعث خرابی خواهد شد.
5 - دلال (Middle man): اگر کلاسی تنها کاری که انجام میدهد انتقال فراخوانی به کلاس دیگری است، دیگر نیازی به این کلاس وجود نخواهد داشت.
اطلاع از الگوهای بد کد نویسی به همان اندازه اطلاع از الگوهای خوب کد نویسی در کیفیت محصول تولیدی اثر مثبت خواهند داشت. یادگیری طبقه بندی شده این الگوها کار را برای استفاده روزمره از آنها آسانتر خواهد کرد.