Это кажется, что Вы в зависимости от некоторой обратной связи для определения то, что застревает на принимающем конце. Необходимо проверять исходящую почту сами на очевидный "spaminess".
Покупают любую достойную систему управления спама и отправляют Вашу исходящую почту через него. При отправке какого-либо достойного объема почты необходимо делать это во всяком случае из-за риска отправки исходящих вирусов, особенно если у Вас есть настольные пользователи Windows.
Proofpoint имел спам + антивирус + некоторые сервисы репутации в единственном развертывании, например. (Я раньше работал там, таким образом, я, оказывается, знаю это первое, что пришло на ум. Я уверен, что у других поставщиков в этом пространстве есть подобные функции.), Но Вы получаете идею. Если Вы отправляете свою почту посредством основной коммерческой установки управления спамом, и она не передает, она не должна выходить из Вашей сети.
кроме того, существуют некоторые компании, которые могут помочь Вам с увеличивающимися уровнями доставки неспама, исходящей электронной почты, как Habeas.
Проблема, с которой вы сталкиваетесь, обычно решается с помощью принципа инверсии зависимостей (также известного как DIP). Исходную статью можно найти здесь .
Статья в основном является объектно-ориентированной, но вы также можете применять объектно-ориентированный язык и на императивном языке (вы можете выполнять объектно-ориентированные операции на императивном языке, это намного сложнее).
Принцип состоит в том, что лучше дать клиентскому объекту ссылку на объект, который выполняет некоторую необходимую обработку (например, доступ к базе данных), чем кодировать или агрегировать этот объект в клиентский объект.
На уровне функции вы можете преобразовать его, чтобы предоставить функции высокого уровня данные / функции низкого уровня.
Лучший способ на языке, отличном от объектно-ориентированного программирования, - это передать структуру или указатель функции, который определяет данные / функции, используемые функция более высокого уровня.
Вы можете предоставить какой-то объект контекста / среды. Скажите:
type Environment = record
DatabaseHandle: ...;
...
end;
Employee = record
ID: integer;
Name: string;
...
end;
function OpenEnvironment (var Env: Environment): boolean;
begin
...
end;
procedure CloseEnvironment (var Env: Environment);
begin
...
end;
function GetEmployeeById (var Env: Environment; ID: integer; var Employee: Employee): boolean;
begin
... load employee using the data source contained in environment ...
end;
(Псевдо-Паскаль). Преимущество состоит в том, что вы можете использовать структуру Environment для хранения, скажем, расширенной информации об ошибках и другого глобального состояния, таким образом избегая PITA, который является Unixish errno или Window GetLastError ]. Еще одно преимущество этого подхода заключается в том, что все ваши API-интерфейсы становятся реентерабельными, и, используя выделенную среду для каждого потока, как следствие, потокобезопасность.
Недостатком этого подхода является то, что вам придется передавать дополнительный аргумент всем вашим API.
Здесь вы можете использовать трехуровневый подход, ваш первый уровень - это ваш клиент , тот, который использует getEmployeePhoneNbr (employeeId) ... второй уровень это ваш уровень доступа к данным , а третий уровень будет уровнем реализации данных , который будет использоваться вашим уровнем доступа к данным для доступа к конкретному источнику информации.
Уровень реализации данных.
Этот уровень содержит:
Уровень доступа к данным
Содержит:
. Используя этот подход, вам нужно будет только позаботиться о предоставлении права структура реализации данных на вашем уровне доступа к данным, поэтому, если она изменится, вам нужно будет изменить ее только в одном месте.
Поместите зависимость ресурса в функцию поиска. Если несколько ресурсов связаны, я бы создал модуль с простыми функциями для их извлечения. Я лично избегаю передавать такие ссылки, когда могу этого избежать. Код в пути не имеет никакого отношения к их знанию или использованию.
Вместо:
getEmployeePhoneNbr(employeeId)
dbName = "employeedb"
... SQL, logic, etc.
Или:
getEmployeePhoneNbr(employeeId, dbName)
... SQL, logic, etc.
Я бы сделал следующее:
getEmployeePhoneNbr(employeeId)
dbName = getEmployeeDbName()
... SQL, logic, etc.
Таким образом вы можете изменить getEmployeeDbName () и все зависимые функции и модули принесет пользу.
Это очень сложный вопрос для решения независимо от того, является ли ваш язык реализации объектно-ориентированным или нет (и в любом случае объектные методологии обычно могут применяться независимо от того, поддерживает ли язык программирования их как язык construct, поэтому я описал свое решение в терминах объектов)
Вы хотели бы иметь возможность одинаково обрабатывать все хранилища данных. В действительности это практически невозможно, и вы должны выбрать парадигму и принять ее ограничения. Например, можно основать дизайн вашей абстракции на парадигме СУБД (подключение / запрос / выборка) и попытаться инкапсулировать доступ к файлам через тот же интерфейс.
Подход, который я успешно использовал, заключается в том, чтобы избежать встраивания получение данных внутри (в вашем случае) объекта "Сотрудник" поскольку это создает связь, которая замыкается между абстракцией Сотрудника в программе и хранением и получением его данных.
Вместо этого я создаю отдельный объект, отвечающий за получение данных для создания объекта Сотрудника, и в Turn построить объект Employee из этих данных. Теперь я могу создать сотрудника из любого источника данных при условии, что я могу преобразовать данные в соответствующую общую структуру. (У меня есть преимущество в языковой поддержке ассоциативных массивов, которая значительно упрощает процесс передачи кортежей, у вас могут возникнуть проблемы, если ваш язык разработки затрудняет или делает невозможным это сделать).
Это также упрощает приложение test, поскольку я могу создать "объект" Employee непосредственно в моем модульном тесте, не беспокоясь о создании источника данных (или о том, остались ли данные, которые были там в прошлый раз). В сложной конструкции эта установка и разборка могут составлять большую часть тестового кода. Кроме того, если возникнет необходимость в создании 1000 «объектов» сотрудников, я могу повторно использовать свой код без необходимости 1000 раз запрашивать мой источник данных (файл, базу данных, индекс карты и т. Д.) (Другими словами, он аккуратно решает знаменитый ORM N + 1).
Итак, чтобы резюмировать, полностью отделить получение данных от бизнес-логики, поскольку скрытая зависимость, которую вы описываете, имеет несколько очень неприятных ошибок. IMHO, это анти-шаблон для инкапсуляции извлечения определенных данных в рамках конструкции «объекта» или в функции для извлечения свойства из некоторых сохраненных данных.
В сложной конструкции эта установка и разборка могут составлять большую часть тестового кода. Кроме того, если возникнет необходимость в создании 1000 «объектов» сотрудников, я могу повторно использовать свой код без необходимости 1000 раз запрашивать мой источник данных (файл, базу данных, индекс карты и т. Д.) (Другими словами, он аккуратно решает знаменитый ORM N + 1).Итак, чтобы резюмировать, полностью отделить получение данных от бизнес-логики, поскольку скрытая зависимость, которую вы описываете, имеет несколько очень неприятных ошибок. ИМХО, это анти-шаблон для инкапсуляции извлечения определенных данных внутри конструкции «объекта» или внутри функции для извлечения свойства из некоторых сохраненных данных.
В сложной конструкции эта установка и разборка могут составлять большую часть тестового кода. Кроме того, если возникнет необходимость в создании 1000 «объектов» сотрудников, я могу повторно использовать свой код без необходимости 1000 раз запрашивать мой источник данных (файл, базу данных, индекс карты и т. Д.) (Другими словами, он аккуратно решает знаменитый ORM N + 1).Итак, чтобы резюмировать, полностью отделить получение данных от бизнес-логики, поскольку скрытая зависимость, которую вы описываете, имеет несколько очень неприятных ошибок. IMHO, это анти-шаблон для инкапсуляции извлечения определенных данных в рамках конструкции «объекта» или в функции для извлечения свойства из некоторых сохраненных данных.
картотека и т. д.) 1000 раз (другими словами, он аккуратно решает знаменитую проблему запроса ORM N + 1).Итак, чтобы резюмировать, полностью отделить получение данных от бизнес-логики, поскольку скрытая зависимость, которую вы описываете, имеет несколько очень неприятных ловушек. IMHO, это анти-шаблон для инкапсуляции извлечения определенных данных в рамках конструкции «объекта» или в функции для извлечения свойства из некоторых сохраненных данных.
картотека и т. д.) 1000 раз (другими словами, он аккуратно решает знаменитую проблему запроса ORM N + 1).Итак, чтобы резюмировать, полностью отделить получение данных от бизнес-логики, поскольку скрытая зависимость, которую вы описываете, имеет несколько очень неприятных ловушек. IMHO, это анти-шаблон для инкапсуляции извлечения определенных данных в рамках конструкции «объекта» или в функции для извлечения свойства из некоторых сохраненных данных.